#!/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 20–28 (days 0–8, patients 1–675): fully completed MCU - every 15th patient: 2-day checkin - April 29 (day 9, patients 676–750): checked in, most stations done - a few lab stations still processing - April 30 (day 10, patients 751–825): ongoing today - 751–810 (60 patients): checked in this morning, partial stations - 811–825 (15 patients): not yet arrived - May 1–9 (days 11–19, patients 826–1500): not yet """ from datetime import date, datetime, timedelta # ── constants ────────────────────────────────────────────────────────────────── MCU_ID = 9999 BASE_ID = 900000 # preregister_id = BASE_ID + i (900001–901500) 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 1–80 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 1–8 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) # 22–55 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 1–8 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 20–28) ────────────────────────────────────── 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 # 1–75 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 61–75: not yet arrived (no checkin, no stations) # ─ resume status & published ───────────────────────────────────────────── # validated: April 20–27 (days 0–7) # published: April 20–25 (days 0–5) 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 0–7) 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))