Files
2026-04-30 14:27:01 +07:00

418 lines
20 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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))