Initial commit

This commit is contained in:
sas.fajri
2026-04-30 14:27:01 +07:00
commit e29e943c27
70 changed files with 8909 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
# Demo Scripts — MCU PROJECT DEMO 2026
Script untuk generate dummy data dan simulasi live MCU berjalan, khusus keperluan demo ke client.
---
## Struktur
```
scripts/
├── demo_seed.py # Generate + jalankan dummy data (1500 pasien, historis + hari ini)
├── demo_live.sh # Simulasi aktivitas MCU berjalan secara real-time
├── demo_cleanup.sql # Hapus semua data demo
└── README.md
```
---
## Quick Start
### 1. Seed data awal (jalankan sekali sebelum demo)
```bash
# Di laptop lokal
python3 scripts/demo_seed.py > /tmp/demo_seed.sql
# Upload + jalankan di server
scp /tmp/demo_seed.sql one@devcpone.aplikasi.web.id:/tmp/
ssh one@devcpone.aplikasi.web.id "mysql -u admin -pSasone\!102938 cpone_dashboard < /tmp/demo_seed.sql"
```
Alternatif one-liner:
```bash
python3 scripts/demo_seed.py | ssh one@devcpone.aplikasi.web.id "mysql -u admin -pSasone\!102938 cpone_dashboard"
```
### 2. Jalankan live simulation
```bash
ssh one@devcpone.aplikasi.web.id
# Kecepatan normal (8 detik per aksi)
/home/one/demo_live.sh
# Lebih cepat untuk demo dinamis (3 detik per aksi)
/home/one/demo_live.sh 3
# Lebih lambat (15 detik per aksi)
/home/one/demo_live.sh 15
# Hentikan: Ctrl+C
```
### 3. Reset data (setelah demo selesai)
```bash
ssh one@devcpone.aplikasi.web.id "mysql -u admin -pSasone\!102938 cpone_dashboard < /tmp/demo_cleanup.sql"
```
---
## Data yang Di-seed
| | Detail |
|---|---|
| **Project** | MCU PROJECT DEMO 2026 — PT DEMO CORPORATION |
| **MCU ID** | 9999 |
| **Periode** | 20 April 2026 10 Mei 2026 |
| **Total pasien** | 1.500 (75/hari selama 20 hari) |
| **Preregister ID range** | 900001 901500 |
### Distribusi skenario
| Tanggal | Pasien | Skenario |
|---------|--------|----------|
| 20 Apr 28 Apr | 1 675 | Sudah selesai semua. Di antara ini, setiap kelipatan 15 (patient ke-15, 30, …) melakukan **2-day check-in**: sebagian station hari 1, sisa station hari 2. |
| 29 Apr | 676 750 | Sudah check-in, nonlab station selesai, **lab station masih processing**. |
| 30 Apr (hari ini) | 751 825 | 751810: sudah check-in pagi, **partial station** (sedang berjalan). 811825: **belum datang** — inilah yang akan di-trigger live script. |
| 1 Mei 9 Mei | 826 1.500 | Belum dijadwalkan. |
### Resume & hasil
| Kondisi | Pasien |
|---------|--------|
| Resume validated ✅ | Apr 2027 (600 pasien) |
| Resume published ✅ | Apr 2025 (375 pasien) |
| PDF tersedia (View PDF) | Pasien 180 (`2026/04/R26040001_*.pdf` dst.) |
| Kelainan / abnormal | ~33% dari pasien validated (~186 rows), 6 grup |
---
## Apa yang Disimulasikan live_demo.sh
Script berjalan infinite loop, cycle 4 aksi secara berurutan:
| Aksi | Yang Terjadi |
|------|-------------|
| **A — Check-in** | Pasien baru dari kelompok "belum datang" (811825) melakukan check-in dengan waktu saat ini |
| **B — Station** | Pasien yang sudah check-in hari ini mendapatkan update station selesai (satu station per siklus) |
| **C — Validasi** | Resume pasien kemarin (Apr 29) divalidasi dokter satu per satu |
| **D — Publish PDF** | Pasien Apr 29 yang sudah divalidasi mendapat file PDF dan statusnya published |
Output di terminal:
```
╔══════════════════════════════════════════════════════════════╗
║ CpOne — DEMO LIVE SIMULATION ║
║ MCU PROJECT DEMO 2026 │ ID: 9999 │ Hari ini: 2026-04-30 ║
╚══════════════════════════════════════════════════════════════╝
Aksi: A=Check-in B=Station C=Validasi D=Publish PDF
Interval: 8s │ Press Ctrl+C untuk berhenti
[10:32:01] ✅ CHECK-IN │ Siti Santoso │ HR │ masuk pukul 10:32:01
[10:32:09] 🏥 STATION │ Budi Wijaya │ Sample Station ECG │ selesai
[10:32:17] ✔ VALIDASI │ Rina Pratama │ resume divalidasi dokter
[10:32:25] 📄 PUBLISH │ Agus Kurnia │ PDF → 2026/04/R2604D76_resume_individu.pdf
```
---
## Tips Demo
**Halaman yang menarik untuk ditunjukkan:**
1. **Dashboard** — pilih tanggal hari ini (30/04/2026) untuk lihat aktivitas real-time
2. **Arrival** — scroll ke bawah, pasien baru akan muncul setiap siklus
3. **Progress** — counter "Validated" dan "Published" naik setiap kali aksi C/D dijalankan
4. **Abnormal** — sudah ada data kelainan dari pasien Apr 2027
5. **Result** — tombol "View PDF" aktif untuk pasien 180 + pasien yang baru di-publish
**Saat demo:**
- Buka dashboard di browser, biarkan live script jalan di background terminal
- Tunjukkan pasien check-in datang satu per satu (Arrival page)
- Tunjukkan station selesai bertahap (Dashboard → Station Status)
- Tunjukkan counter validated/published naik (Progress page)
- Tunjukkan PDF bisa dibuka (Result page → tombol View PDF)
---
## Re-seed Ulang
Kalau data ingin di-reset ke kondisi awal (misal setelah demo):
```bash
# Dari laptop lokal, jalankan ulang seed
python3 scripts/demo_seed.py | ssh one@devcpone.aplikasi.web.id "mysql -u admin -pSasone\!102938 cpone_dashboard"
```
Script seed sudah idempotent — DELETE data lama dulu sebelum INSERT baru.

View File

@@ -0,0 +1,19 @@
-- demo_cleanup.sql — Remove all demo data (MCU ID=9999)
-- Usage: mysql -u admin -pSasone!102938 cpone_dashboard < demo_cleanup.sql
SET FOREIGN_KEY_CHECKS = 0;
DELETE FROM mcu_station_progress WHERE Mcu_StationProgressMcuID = 9999;
DELETE FROM mcu_checkinout WHERE Mcu_CheckinoutMcuID = 9999;
DELETE FROM mcu_patient_required_station WHERE mcu_id = 9999;
DELETE FROM mcu_patient_schedule WHERE Mcu_PatientSchedulePreregisterID BETWEEN 900001 AND 901500;
DELETE FROM mcu_patient_resume_status WHERE Mcu_PatientResumeStatusMcuID = 9999;
DELETE FROM published_mcu_dashboard_sync WHERE Published_McuDasboardT_OrderHeaderID BETWEEN 900001 AND 901500;
DELETE FROM kelainan_details WHERE Mgm_McuID = 9999;
DELETE FROM mcu_participant_daily WHERE Mcu_ParticipantDailyMcuID = 9999;
DELETE FROM mcu_patient WHERE Mcu_PatientMcuID = 9999;
DELETE FROM mcu_project WHERE Mcu_ProjectMcuID = 9999;
SET FOREIGN_KEY_CHECKS = 1;
SELECT 'Demo data removed.' AS status;

View File

@@ -0,0 +1,293 @@
#!/usr/bin/env bash
# demo_live.sh — Simulate live ongoing MCU activity for demo
#
# Usage:
# ./demo_live.sh # default: 1 action every 8 seconds
# ./demo_live.sh 3 # 1 action every 3 seconds (faster)
# ./demo_live.sh 15 # 1 action every 15 seconds (slower)
#
# What it simulates (cycles through 4 action types):
# A — New patient check-in for today (April 30, patients 811825)
# B — Station progress update for today's in-progress patients
# C — Doctor validates a yesterday resume (April 29)
# D — Publish result PDF (April 29 patient gets a file URL)
#
# Press Ctrl+C to stop.
set -euo pipefail
MCU_ID=9999
TODAY="2026-04-30"
SPEED="${1:-8}"
DB() { mysql -u admin -p'Sasone!102938' cpone_dashboard -sN -e "$1" 2>/dev/null; }
DB_EXEC() { mysql -u admin -p'Sasone!102938' cpone_dashboard -e "$1" 2>/dev/null; }
PDF_BASE_DIR="/home/one/project/one/dashboard-files/2026/04"
PDF_SOURCE="/home/one/project/one/dashboard-files/2024/09/R2409170003_resume_individu.pdf"
PDF_DB_PATH="2026/04"
NOW_TS() { date '+%Y-%m-%d %H:%M:%S'; }
LOG() { printf "[%s] %s\n" "$(date '+%H:%M:%S')" "$1"; }
# ── counters ──────────────────────────────────────────────────────────────────
action_cycle=0
# ── ACTION A: new check-in ────────────────────────────────────────────────────
action_checkin() {
local patient
patient=$(DB "
SELECT mp.Mcu_PatientPreregisterID
FROM mcu_patient mp
WHERE mp.Mcu_PatientMcuID = $MCU_ID
AND mp.Mcu_PatientPreregisterID NOT IN (
SELECT Mcu_CheckinoutPreregisterID
FROM mcu_checkinout
WHERE Mcu_CheckinoutMcuID = $MCU_ID
AND Mcu_CheckinoutDate = '$TODAY'
)
AND mp.Mcu_PatientPreregisterID BETWEEN 900811 AND 900825
ORDER BY mp.Mcu_PatientPreregisterID
LIMIT 1;
")
if [ -z "$patient" ]; then
LOG "⏩ Semua pasien hari ini sudah check-in"
return
fi
local pid=$patient
local oid=$patient
local name
name=$(DB "SELECT Mcu_PatientName FROM mcu_patient WHERE Mcu_PatientPreregisterID = $pid;")
local dept
dept=$(DB "SELECT Mcu_PatientDepartment FROM mcu_patient WHERE Mcu_PatientPreregisterID = $pid;")
local now_time
now_time=$(date '+%H:%M:%S')
DB_EXEC "
INSERT INTO mcu_checkinout
(Mcu_CheckinoutMcuID, Mcu_CheckinoutPreregisterID, Mcu_CheckinoutOrderID,
Mcu_CheckinoutDate, Mcu_CheckinoutInTime, Mcu_CheckinoutOutTime,
Mcu_CheckinoutIsActive, Mcu_CheckinoutSyncedAt)
VALUES
($MCU_ID, $pid, $oid, '$TODAY', '$now_time', NULL, 'Y', NOW());
"
LOG "✅ CHECK-IN │ $name$dept │ masuk pukul $now_time"
}
# ── ACTION B: station progress update ────────────────────────────────────────
action_station() {
# Pick a patient checked in today with at least one required station not yet done
# Station IDs that are part of the MCU package
local ALL_STATIONS="1,31,17,4,5,2,7,33"
local patient
patient=$(DB "
SELECT c.Mcu_CheckinoutPreregisterID
FROM mcu_checkinout c
WHERE c.Mcu_CheckinoutMcuID = $MCU_ID
AND c.Mcu_CheckinoutDate = '$TODAY'
AND (
SELECT COUNT(DISTINCT sp.Mcu_StationProgressStationID)
FROM mcu_station_progress sp
WHERE sp.Mcu_StationProgressPreregisterID = c.Mcu_CheckinoutPreregisterID
AND sp.Mcu_StationProgressMcuID = $MCU_ID
AND sp.Mcu_StationProgressStationID IN ($ALL_STATIONS)
) < 8
ORDER BY c.Mcu_CheckinoutPreregisterID
LIMIT 1;
")
if [ -z "$patient" ]; then
LOG "⏩ Semua station sudah diproses untuk pasien hari ini"
return
fi
local pid=$patient
local oid=$patient
local name
name=$(DB "SELECT Mcu_PatientName FROM mcu_patient WHERE Mcu_PatientPreregisterID = $pid;")
# Get next station not yet done (from the 8-station package)
local station_row
station_row=$(DB "
SELECT s.sid, s.sname, s.src
FROM (
SELECT 1 AS sid, 'Sample Station Phlebotomy' AS sname, 'lab' AS src UNION ALL
SELECT 31,'Sample Station Urine','lab' UNION ALL
SELECT 17,'Sample Station TB/BB','nonlab' UNION ALL
SELECT 4, 'Sample Station Treadmill','nonlab' UNION ALL
SELECT 5, 'Sample Station ECG','nonlab' UNION ALL
SELECT 2, 'Sample Station Rontgen','nonlab' UNION ALL
SELECT 7, 'Sample Station Pemeriksaan Fisik','nonlab' UNION ALL
SELECT 33,'Sample Station Visus dan Buta Warna','nonlab'
) s
WHERE s.sid NOT IN (
SELECT Mcu_StationProgressStationID
FROM mcu_station_progress
WHERE Mcu_StationProgressPreregisterID = $pid
AND Mcu_StationProgressMcuID = $MCU_ID
)
LIMIT 1;
")
if [ -z "$station_row" ]; then
return
fi
local sid sname src
sid=$(echo "$station_row" | cut -f1)
sname=$(echo "$station_row" | cut -f2)
src=$(echo "$station_row" | cut -f3)
local now_ts
now_ts=$(NOW_TS)
if [ "$src" = "lab" ]; then
DB_EXEC "
INSERT INTO mcu_station_progress
(Mcu_StationProgressOrderID, Mcu_StationProgressPreregisterID, Mcu_StationProgressMcuID,
Mcu_StationProgressStationID, Mcu_StationProgressStationName, Mcu_StationProgressSource,
Mcu_StationProgressCheckinDate, Mcu_StationProgressSamplingAt, Mcu_StationProgressReceiveAt,
Mcu_StationProgressProcessAt, Mcu_StationProgressDoneAt, Mcu_StationProgressSyncedAt)
VALUES
($oid, $pid, $MCU_ID, $sid, '$sname', 'lab',
'$TODAY',
DATE_SUB('$now_ts', INTERVAL 45 MINUTE),
DATE_SUB('$now_ts', INTERVAL 30 MINUTE),
DATE_SUB('$now_ts', INTERVAL 10 MINUTE),
'$now_ts', NOW())
ON DUPLICATE KEY UPDATE
Mcu_StationProgressDoneAt = '$now_ts',
Mcu_StationProgressSyncedAt = NOW();
"
else
DB_EXEC "
INSERT INTO mcu_station_progress
(Mcu_StationProgressOrderID, Mcu_StationProgressPreregisterID, Mcu_StationProgressMcuID,
Mcu_StationProgressStationID, Mcu_StationProgressStationName, Mcu_StationProgressSource,
Mcu_StationProgressCheckinDate, Mcu_StationProgressSamplingAt, Mcu_StationProgressReceiveAt,
Mcu_StationProgressProcessAt, Mcu_StationProgressDoneAt, Mcu_StationProgressSyncedAt)
VALUES
($oid, $pid, $MCU_ID, $sid, '$sname', 'nonlab',
'$TODAY', NULL, NULL,
DATE_SUB('$now_ts', INTERVAL 15 MINUTE),
'$now_ts', NOW())
ON DUPLICATE KEY UPDATE
Mcu_StationProgressDoneAt = '$now_ts',
Mcu_StationProgressSyncedAt = NOW();
"
fi
LOG "🏥 STATION │ $name$sname │ selesai"
}
# ── ACTION C: validate resume ─────────────────────────────────────────────────
action_validate() {
local patient
patient=$(DB "
SELECT rs.Mcu_PatientResumeStatusPreregisterID
FROM mcu_patient_resume_status rs
JOIN mcu_patient mp ON mp.Mcu_PatientPreregisterID = rs.Mcu_PatientResumeStatusPreregisterID
WHERE rs.Mcu_PatientResumeStatusMcuID = $MCU_ID
AND rs.Mcu_PatientResumeStatusValidated = 'N'
AND mp.Mcu_PatientPreregisterID BETWEEN 900676 AND 900750
ORDER BY rs.Mcu_PatientResumeStatusPreregisterID
LIMIT 1;
")
if [ -z "$patient" ]; then
LOG "⏩ Semua resume kemarin sudah divalidasi"
return
fi
local name
name=$(DB "SELECT Mcu_PatientName FROM mcu_patient WHERE Mcu_PatientPreregisterID = $patient;")
DB_EXEC "
UPDATE mcu_patient_resume_status
SET Mcu_PatientResumeStatusValidated = 'Y',
Mcu_PatientResumeStatusStatus = 'DONE',
Mcu_PatientResumeSyncedAt = NOW()
WHERE Mcu_PatientResumeStatusPreregisterID = $patient
AND Mcu_PatientResumeStatusMcuID = $MCU_ID;
"
LOG "✔ VALIDASI │ $name │ resume divalidasi dokter"
}
# ── ACTION D: publish PDF ─────────────────────────────────────────────────────
action_publish() {
local order_id
order_id=$(DB "
SELECT rs.Mcu_PatientResumeStatusPreregisterID
FROM mcu_patient_resume_status rs
WHERE rs.Mcu_PatientResumeStatusMcuID = $MCU_ID
AND rs.Mcu_PatientResumeStatusValidated = 'Y'
AND rs.Mcu_PatientResumeStatusPublished = 'N'
AND rs.Mcu_PatientResumeStatusPreregisterID BETWEEN 900676 AND 900825
AND EXISTS (
SELECT 1 FROM published_mcu_dashboard_sync p
WHERE p.Published_McuDasboardT_OrderHeaderID = rs.Mcu_PatientResumeStatusPreregisterID
AND (p.Published_McuDasboardFileUrl IS NULL OR p.Published_McuDasboardFileUrl = '')
)
ORDER BY rs.Mcu_PatientResumeStatusPreregisterID
LIMIT 1;
")
if [ -z "$order_id" ]; then
LOG "⏩ Tidak ada resume validated yang bisa dipublish saat ini"
return
fi
local name
name=$(DB "SELECT Mcu_PatientName FROM mcu_patient WHERE Mcu_PatientPreregisterID = $order_id;")
# seq number for PDF filename: use order_id offset
local seq=$(( order_id - 900000 ))
local fname="R2604D${seq}_resume_individu.pdf"
local fpath="$PDF_BASE_DIR/$fname"
local db_path="$PDF_DB_PATH/$fname"
# Copy PDF file
mkdir -p "$PDF_BASE_DIR"
cp "$PDF_SOURCE" "$fpath" 2>/dev/null || true
# Update database
DB_EXEC "
UPDATE published_mcu_dashboard_sync
SET Published_McuDasboardFileUrl = '$db_path',
Published_McuDasboardStatus = 'Y',
Published_McuDasboardLastUpdated = NOW()
WHERE Published_McuDasboardT_OrderHeaderID = $order_id;
UPDATE mcu_patient_resume_status
SET Mcu_PatientResumeStatusPublished = 'Y',
Mcu_PatientResumeSyncedAt = NOW()
WHERE Mcu_PatientResumeStatusPreregisterID = $order_id
AND Mcu_PatientResumeStatusMcuID = $MCU_ID;
"
LOG "📄 PUBLISH │ $name │ PDF → $db_path"
}
# ── main loop ─────────────────────────────────────────────────────────────────
echo "╔══════════════════════════════════════════════════════════════╗"
echo "║ CpOne — DEMO LIVE SIMULATION ║"
echo "║ MCU PROJECT DEMO 2026 │ ID: $MCU_ID │ Hari ini: $TODAY"
echo "╚══════════════════════════════════════════════════════════════╝"
echo ""
echo " Aksi: A=Check-in B=Station C=Validasi D=Publish PDF"
echo " Interval: ${SPEED}s │ Ctrl+C untuk berhenti"
echo ""
actions=(A B C D)
idx=0
while true; do
act="${actions[$((idx % 4))]}"
case "$act" in
A) action_checkin ;;
B) action_station ;;
C) action_validate ;;
D) action_publish ;;
esac
idx=$(( idx + 1 ))
sleep "$SPEED"
done

View File

@@ -0,0 +1,417 @@
#!/usr/bin/env python3
"""
demo_seed.py — Generate demo data for MCU PROJECT DEMO 2026 (ID=9999)
Usage: python3 demo_seed.py | mysql -u admin -pSasone!102938 cpone_dashboard
Data distribution:
- 1500 patients, 75/day over April 20 May 9, 2026
- April 2028 (days 08, patients 1675): fully completed MCU
- every 15th patient: 2-day checkin
- April 29 (day 9, patients 676750): checked in, most stations done
- a few lab stations still processing
- April 30 (day 10, patients 751825): ongoing today
- 751810 (60 patients): checked in this morning, partial stations
- 811825 (15 patients): not yet arrived
- May 19 (days 1119, patients 8261500): not yet
"""
from datetime import date, datetime, timedelta
# ── constants ──────────────────────────────────────────────────────────────────
MCU_ID = 9999
BASE_ID = 900000 # preregister_id = BASE_ID + i (900001901500)
START_DATE = date(2026, 4, 20)
TODAY = date(2026, 4, 30)
N_PATIENTS = 1500
PER_DAY = 75
MALE_FIRST = ['Budi','Agus','Deni','Rizki','Hendra','Andi','Fajar','Rendi',
'Wahyu','Dito','Bagas','Kevin','Andre','Yoga','Raka','Faisal',
'Eko','Iwan','Joko','Teguh']
FEMALE_FIRST= ['Siti','Ani','Dewi','Rina','Fitri','Nurul','Lilis','Putri',
'Nadya','Citra','Alya','Sinta','Nabila','Dian','Reni','Maya',
'Ira','Yuni','Wati','Tini']
LAST_NAMES = ['Santoso','Wijaya','Pratama','Kurnia','Saputra','Wulandari',
'Lestari','Nugroho','Halim','Sari','Rahman','Hidayat',
'Firmansyah','Kusuma','Raharjo','Setiawan','Wahyudi','Susanto',
'Purnomo','Hakim','Mulyadi','Astuti','Permata','Handoko','Budiman']
DEPTS = ['HR','Finance','Production','Engineering','IT','QA','Procurement',
'Warehouse','Security','Marketing','Legal','Operations','HSE',
'Maintenance','Accounting','Sales','Logistics','R&D','Admin','Management']
POSITIONS = ['Staff','Supervisor','Manager','Operator','Technician','Analyst',
'Coordinator','Head','Specialist','Officer','Inspector','Foreman',
'Executive','Director','Senior Staff']
# stations: (station_id, name, source)
STATIONS = [
(1, 'Sample Station Phlebotomy', 'lab'),
(31, 'Sample Station Urine', 'lab'),
(17, 'Sample Station TB/BB', 'nonlab'),
(4, 'Sample Station Treadmill', 'nonlab'),
(5, 'Sample Station ECG', 'nonlab'),
(2, 'Sample Station Rontgen', 'nonlab'),
(7, 'Sample Station Pemeriksaan Fisik', 'nonlab'),
(33, 'Sample Station Visus dan Buta Warna','nonlab'),
]
KELAINAN_GROUPS = [
('BMI', 'BMI Abnormal', 0.28),
('Hipertensi', 'Hipertensi', 0.15),
('Kelainan Visus', 'Kelainan Refraksi', 0.20),
('Ganguan Metabolisme Lemak', 'Dislipidemia', 0.12),
('Kelainan Hematologi', 'Hemoglobin Rendah', 0.08),
('Kelainan Fisik', 'Kelainan Muskuloskeletal', 0.10),
]
FITNESS_CATS = {
'BMI': ('Fit dengan Catatan', 'Fit with Note', 2),
'Hipertensi': ('Tidak Fit Sementara','Temporary Unfit',3),
'Kelainan Visus': ('Fit dengan Catatan', 'Fit with Note', 2),
'Ganguan Metabolisme Lemak': ('Fit dengan Catatan', 'Fit with Note', 2),
'Kelainan Hematologi': ('Fit dengan Catatan', 'Fit with Note', 2),
'Kelainan Fisik': ('Fit dengan Catatan', 'Fit with Note', 2),
}
PDF_BASE = '2026/04'
PDF_COUNT = 80 # patients 180 get a PDF file
lines = []
def q(s):
if s is None:
return 'NULL'
return "'" + str(s).replace("'", "''") + "'"
def dt(d, h, m, extra_min=0):
"""Return DATETIME string for date d, time h:m plus extra_min."""
base = datetime(d.year, d.month, d.day, h, m)
base += timedelta(minutes=extra_min)
return base.strftime('%Y-%m-%d %H:%M:%S')
# ── header ─────────────────────────────────────────────────────────────────────
lines.append("SET FOREIGN_KEY_CHECKS = 0;")
lines.append("SET @mcu = 9999;")
lines.append("")
# ── cleanup ────────────────────────────────────────────────────────────────────
lines.append("-- cleanup existing demo data")
lines.append("DELETE FROM mcu_station_progress WHERE Mcu_StationProgressMcuID = 9999;")
lines.append("DELETE FROM mcu_checkinout WHERE Mcu_CheckinoutMcuID = 9999;")
lines.append("DELETE FROM mcu_patient_required_station WHERE preregister_id BETWEEN 900001 AND 901500;")
lines.append("DELETE FROM mcu_patient_schedule WHERE Mcu_PatientSchedulePreregisterID BETWEEN 900001 AND 901500;")
lines.append("DELETE FROM mcu_patient_resume_status WHERE Mcu_PatientResumeStatusMcuID = 9999;")
lines.append("DELETE FROM published_mcu_dashboard_sync WHERE Published_McuDasboardT_OrderHeaderID BETWEEN 900001 AND 901500;")
lines.append("DELETE FROM kelainan_details WHERE Mgm_McuID = 9999;")
lines.append("DELETE FROM mcu_participant_daily WHERE Mcu_ParticipantDailyMcuID = 9999;")
lines.append("DELETE FROM mcu_patient WHERE Mcu_PatientMcuID = 9999;")
lines.append("DELETE FROM mcu_project WHERE Mcu_ProjectMcuID = 9999;")
lines.append("")
# ── project ────────────────────────────────────────────────────────────────────
lines.append("-- project")
lines.append(
"INSERT INTO mcu_project "
"(Mcu_ProjectMcuID, Mcu_ProjectCorporateID, Mcu_ProjectCorporateName, "
" Mcu_ProjectNumber, Mcu_ProjectLabel, Mcu_ProjectBranchID, "
" Mcu_ProjectStartDate, Mcu_ProjectEndDate, "
" Mcu_ProjectIsActive, Mcu_ProjectTotalParticipant, Mcu_ProjectSyncedAt) "
"VALUES "
f"(9999, 9999, 'PT DEMO CORPORATION', 'MCU-DEMO-2026', 'MCU PROJECT DEMO 2026', "
f"1, '2026-04-20', '2026-05-10', 'Y', 1500, NOW());"
)
lines.append("")
# ── participant daily ──────────────────────────────────────────────────────────
lines.append("-- participant daily totals")
daily_rows = []
for day_idx in range(20):
d = START_DATE + timedelta(days=day_idx)
daily_rows.append(
f"(9999, '{d}', {PER_DAY}, 'Y', NOW(), NOW())"
)
lines.append(
"INSERT INTO mcu_participant_daily "
"(Mcu_ParticipantDailyMcuID, Mcu_ParticipantDailyDate, Mcu_ParticipantDailyTotal, "
" Mcu_ParticipantDailyIsActive, Mcu_ParticipantDailyCreated, Mcu_ParticipantDailyLastUpdated) "
"VALUES\n " + ",\n ".join(daily_rows) + ";"
)
lines.append("")
# ── patients, schedules, required stations, checkinout, stations ───────────────
patient_rows = []
schedule_rows = []
req_station_rows = [] # location_id 18 per station, unique per (preregister_id, location_id)
checkin_rows = []
station_rows = []
resume_rows = []
published_rows = []
kelainan_rows = []
for i in range(1, N_PATIENTS + 1):
pid = BASE_ID + i # preregister_id
oid = BASE_ID + i # order_id (same for simplicity)
day_idx = (i - 1) // PER_DAY
sched_date = START_DATE + timedelta(days=day_idx)
# name / gender
g_idx = (i - 1) % 40
if g_idx < 20:
gender = 'Male'
first = MALE_FIRST[g_idx % len(MALE_FIRST)]
else:
gender = 'Female'
first = FEMALE_FIRST[(g_idx - 20) % len(FEMALE_FIRST)]
last = LAST_NAMES[(i + 7) % len(LAST_NAMES)]
name = f"{first} {last}"
nip = f"EMP{pid}"
dept = DEPTS[(i + 3) % len(DEPTS)]
posisi = POSITIONS[i % len(POSITIONS)]
age = 22 + ((i * 3 + 7) % 34) # 2255
dob = date(2026 - age, 1, 1).isoformat()
lab_no = f"R2604{i:04d}"
patient_rows.append(
f"({pid}, {MCU_ID}, {q(name)}, {q(nip)}, {q(gender)}, "
f"{q(dob)}, {age}, {q(dept)}, {q(posisi)}, "
f"{oid}, 'Y', 'Y', NOW())"
)
schedule_rows.append(
f"({pid}, '{sched_date}', 'Y', NOW())"
)
# required stations — location_id 18 per station so unique key (preregister_id, location_id) holds
for loc_id, (sid, sname, _) in enumerate(STATIONS, start=1):
req_station_rows.append(
f"({MCU_ID}, {pid}, {oid}, {loc_id}, {sid}, {q(sname)})"
)
# ─ checkinout & station progress ─────────────────────────────────────────
is_two_day = (i % 15 == 0) and (sched_date <= date(2026, 4, 28))
cin_h = 7 + (i % 3)
cin_m = (i * 7) % 60
def add_checkin(d, h, m, out_offset_min):
ci = dt(d, h, m)
co = dt(d, h, m, out_offset_min) if out_offset_min else 'NULL'
co_val = q(co) if out_offset_min else 'NULL'
checkin_rows.append(
f"({MCU_ID}, {pid}, {oid}, '{d}', '{h:02d}:{m:02d}:00', {co_val}, 'Y', NOW())"
)
def add_station(d, sid, sname, src, sampling_off, recv_off, proc_off, done_off):
"""All offsets in minutes from d h:m; None = NULL."""
base_h, base_m = cin_h, cin_m
def ts(off):
if off is None: return 'NULL'
return q(dt(d, base_h, base_m, off))
if src == 'lab':
station_rows.append(
f"({oid}, {pid}, {MCU_ID}, {sid}, {q(sname)}, {q(src)}, '{d}', "
f"{ts(sampling_off)}, {ts(recv_off)}, {ts(proc_off)}, {ts(done_off)}, NOW())"
)
else:
station_rows.append(
f"({oid}, {pid}, {MCU_ID}, {sid}, {q(sname)}, {q(src)}, '{d}', "
f"NULL, NULL, {ts(proc_off)}, {ts(done_off)}, NOW())"
)
# ─ CASE 1: fully done (April 2028) ──────────────────────────────────────
if sched_date < date(2026, 4, 29):
if is_two_day:
# day 1: 4 stations, day 2: remaining 4
add_checkin(sched_date, cin_h, cin_m, 200)
# day 1 stations
add_station(sched_date, 1, 'Sample Station Phlebotomy', 'lab', 30, 45, 90, 120)
add_station(sched_date, 31, 'Sample Station Urine', 'lab', 20, 35, 75, 95)
add_station(sched_date, 17, 'Sample Station TB/BB', 'nonlab', None,None, 15, 25)
add_station(sched_date, 4, 'Sample Station Treadmill', 'nonlab', None,None, 45, 65)
# day 2
d2 = sched_date + timedelta(days=1)
add_checkin(d2, 8, 0, 180)
# for day2 stations, use 8:00 as base — override cin_h/cin_m temporarily
orig_h, orig_m = cin_h, cin_m
cin_h, cin_m = 8, 0
add_station(d2, 5, 'Sample Station ECG', 'nonlab', None,None, 20, 35)
add_station(d2, 2, 'Sample Station Rontgen', 'nonlab', None,None, 50, 70)
add_station(d2, 7, 'Sample Station Pemeriksaan Fisik', 'nonlab', None,None, 80, 100)
add_station(d2, 33, 'Sample Station Visus dan Buta Warna','nonlab', None,None,115, 135)
cin_h, cin_m = orig_h, orig_m
else:
add_checkin(sched_date, cin_h, cin_m, 240 + (i % 60))
add_station(sched_date, 1, 'Sample Station Phlebotomy', 'lab', 30, 45, 90, 120)
add_station(sched_date, 31, 'Sample Station Urine', 'lab', 20, 35, 75, 95)
add_station(sched_date, 17, 'Sample Station TB/BB', 'nonlab', None,None, 15, 25)
add_station(sched_date, 4, 'Sample Station Treadmill', 'nonlab', None,None, 45, 65)
add_station(sched_date, 5, 'Sample Station ECG', 'nonlab', None,None, 75, 95)
add_station(sched_date, 2, 'Sample Station Rontgen', 'nonlab', None,None,110, 130)
add_station(sched_date, 7, 'Sample Station Pemeriksaan Fisik', 'nonlab', None,None,145, 165)
add_station(sched_date, 33, 'Sample Station Visus dan Buta Warna','nonlab',None,None,175, 200)
# ─ CASE 2: April 29 — checked in, most stations done ────────────────────
elif sched_date == date(2026, 4, 29):
add_checkin(sched_date, cin_h, cin_m, None) # no checkout yet
add_station(sched_date, 17, 'Sample Station TB/BB', 'nonlab', None,None, 15, 25)
add_station(sched_date, 4, 'Sample Station Treadmill', 'nonlab', None,None, 45, 65)
add_station(sched_date, 5, 'Sample Station ECG', 'nonlab', None,None, 80, 95)
add_station(sched_date, 2, 'Sample Station Rontgen', 'nonlab', None,None, 110, 130)
add_station(sched_date, 7, 'Sample Station Pemeriksaan Fisik', 'nonlab', None,None, 145, 165)
add_station(sched_date, 33, 'Sample Station Visus dan Buta Warna','nonlab',None,None, 175, 195)
# some patients: lab still processing
if i % 4 == 0:
# lab done
add_station(sched_date, 1, 'Sample Station Phlebotomy', 'lab', 30, 45, 90, 120)
add_station(sched_date, 31, 'Sample Station Urine', 'lab', 20, 35, 75, 95)
else:
# lab in process — no DoneAt
add_station(sched_date, 1, 'Sample Station Phlebotomy', 'lab', 30, 45, None, None)
add_station(sched_date, 31, 'Sample Station Urine', 'lab', 20, 35, None, None)
# ─ CASE 3: April 30 — today ──────────────────────────────────────────────
elif sched_date == TODAY:
local_idx = i - 750 # 175 within today
if local_idx <= 60:
# arrived this morning — partial stations
add_checkin(sched_date, cin_h, cin_m, None)
add_station(sched_date, 17, 'Sample Station TB/BB', 'nonlab', None,None, 15, 25)
add_station(sched_date, 4, 'Sample Station Treadmill', 'nonlab', None,None, 45, 65)
if local_idx % 3 == 0:
# 20 patients done 3 stations
add_station(sched_date, 5, 'Sample Station ECG', 'nonlab', None,None, 80, 95)
if local_idx % 5 == 0:
# 12 patients done lab too
add_station(sched_date, 1, 'Sample Station Phlebotomy', 'lab', 30, 45, None, None)
add_station(sched_date, 31, 'Sample Station Urine', 'lab', 20, 35, None, None)
# patients 6175: not yet arrived (no checkin, no stations)
# ─ resume status & published ─────────────────────────────────────────────
# validated: April 2027 (days 07)
# published: April 2025 (days 05)
if day_idx <= 7:
validated = 'Y'
status = 'DONE'
else:
validated = 'N'
status = ''
published = 'Y' if day_idx <= 5 else 'N'
if sched_date < TODAY:
resume_rows.append(
f"({pid}, {MCU_ID}, {q(status)}, {q(validated)}, {q(published)}, NOW())"
)
# published_mcu_dashboard_sync — all patients from sched < today get a row
if sched_date < TODAY:
has_pdf = (i <= PDF_COUNT)
file_url = f"'{PDF_BASE}/R2604{i:04d}_resume_individu.pdf'" if has_pdf else 'NULL'
pdf_status = 'Y' if has_pdf else 'N'
published_rows.append(
f"({oid}, {q(pdf_status)}, {file_url}, 'Y', NOW(), 0, NOW(), 0)"
)
# kelainan_details — ~33% of validated patients (days 07)
if day_idx <= 7 and validated == 'Y' and i % 3 == 0:
for (grp, kname, prob) in KELAINAN_GROUPS:
# Use deterministic threshold based on i and grp index
grp_idx = KELAINAN_GROUPS.index((grp, kname, prob))
threshold = int(prob * 100)
if (i + grp_idx * 17) % 100 < threshold:
fcat_name, fcat_eng, fcat_lvl = FITNESS_CATS[grp]
kelainan_rows.append(
f"('MCU-DEMO-2026', {oid}, '{sched_date} 08:00:00', {q(lab_no)}, "
f"{age}, {pid}, {q(gender)}, {q(nip)}, {q(dept)}, {q(dept)}, "
f"{q(name)}, {q(name)}, {q(grp)}, 1, {q(kname)}, {q(kname)}, "
f"1, {q(kname)}, 1, {q(grp)}, "
f"1, {q(fcat_name)}, {q(fcat_eng)}, {fcat_lvl}, "
f"{MCU_ID}, NULL, NULL)"
)
# ── batch insert helpers ───────────────────────────────────────────────────────
CHUNK = 200
def emit_inserts(table, cols, rows, chunk=CHUNK):
if not rows:
return
lines.append(f"-- {table} ({len(rows)} rows)")
for start in range(0, len(rows), chunk):
batch = rows[start:start+chunk]
lines.append(
f"INSERT INTO {table} ({cols}) VALUES\n " +
",\n ".join(batch) + ";"
)
lines.append("")
emit_inserts(
"mcu_patient",
"Mcu_PatientPreregisterID, Mcu_PatientMcuID, Mcu_PatientName, Mcu_PatientNIP, "
"Mcu_PatientGender, Mcu_PatientDOB, Mcu_PatientAge, Mcu_PatientDepartment, "
"Mcu_PatientPosisi, Mcu_PatientOrderID, Mcu_PatientIsRegistered, Mcu_PatientIsActive, "
"Mcu_PatientSyncedAt",
patient_rows
)
emit_inserts(
"mcu_patient_schedule",
"Mcu_PatientSchedulePreregisterID, Mcu_PatientScheduleDate, "
"Mcu_PatientScheduleIsActive, Mcu_PatientScheduleSyncedAt",
schedule_rows
)
emit_inserts(
"mcu_patient_required_station",
"mcu_id, preregister_id, order_header_id, location_id, sample_station_id, station_name",
req_station_rows
)
emit_inserts(
"mcu_checkinout",
"Mcu_CheckinoutMcuID, Mcu_CheckinoutPreregisterID, Mcu_CheckinoutOrderID, "
"Mcu_CheckinoutDate, Mcu_CheckinoutInTime, Mcu_CheckinoutOutTime, "
"Mcu_CheckinoutIsActive, Mcu_CheckinoutSyncedAt",
checkin_rows
)
emit_inserts(
"mcu_station_progress",
"Mcu_StationProgressOrderID, Mcu_StationProgressPreregisterID, Mcu_StationProgressMcuID, "
"Mcu_StationProgressStationID, Mcu_StationProgressStationName, Mcu_StationProgressSource, "
"Mcu_StationProgressCheckinDate, Mcu_StationProgressSamplingAt, Mcu_StationProgressReceiveAt, "
"Mcu_StationProgressProcessAt, Mcu_StationProgressDoneAt, Mcu_StationProgressSyncedAt",
station_rows
)
emit_inserts(
"mcu_patient_resume_status",
"Mcu_PatientResumeStatusPreregisterID, Mcu_PatientResumeStatusMcuID, "
"Mcu_PatientResumeStatusStatus, Mcu_PatientResumeStatusValidated, "
"Mcu_PatientResumeStatusPublished, Mcu_PatientResumeSyncedAt",
resume_rows
)
emit_inserts(
"published_mcu_dashboard_sync",
"Published_McuDasboardT_OrderHeaderID, Published_McuDasboardStatus, "
"Published_McuDasboardFileUrl, Published_McuDasboardIsActive, "
"Published_McuDasboardCreated, Published_McuDasboardCreatedUserID, "
"Published_McuDasboardLastUpdated, Published_McuDasboardLastUpdatedUserID",
published_rows
)
emit_inserts(
"kelainan_details",
"Numbering, T_OrderHeaderID, T_OrderHeaderDate, T_OrderHeaderLabNumber, "
"AgePatient, M_PatientID, M_PatientGender, M_PatientNIP, "
"M_PatientDepartement, M_PatientDivisi, PatientName, M_PatientName, "
"GroupResult, Nat_TestID, Nat_TestCode, Nat_TestName, "
"Mcu_KelainanID, Mcu_KelainanName, Mcu_KelainanGroupSummaryID, Mcu_KelainanGroupSummaryName, "
"Mcu_FitnessCategoryID, Mcu_FitnessCategoryName, Mcu_FitnessCategoryEng, Mcu_FitnessCategoryLevel, "
"Mgm_McuID, Mcu_GenerateID, Mcu_ProjectID",
kelainan_rows
)
lines.append("SET FOREIGN_KEY_CHECKS = 1;")
lines.append("SELECT 'Demo data seeded successfully.' AS status;")
print('\n'.join(lines))