package progress import ( "cpone-dashboard/db" "strings" ) type ProgressRow struct { PreregisterID int NIP string Name string Posisi string ResumeStatus string Validated string Published string } type ProgressSummary struct { Total int Validated int Published int } func GetProgressRows(mcuID int) ([]ProgressRow, error) { rows, err := db.DB.Query(` SELECT mp.Mcu_PatientPreregisterID, COALESCE(NULLIF(TRIM(mp.Mcu_PatientNIP), ''), '-') AS nip, COALESCE(NULLIF(TRIM(mp.Mcu_PatientName), ''), '-') AS name, COALESCE( NULLIF(TRIM(mp.Mcu_PatientDepartment), ''), NULLIF(TRIM(mp.Mcu_PatientDivision), ''), NULLIF(TRIM(mp.Mcu_PatientPosisi), ''), '-' ) AS posisi, COALESCE(rs.Mcu_PatientResumeStatusStatus, '') AS resume_status, COALESCE(rs.Mcu_PatientResumeStatusValidated, 'N') AS validated, COALESCE(rs.Mcu_PatientResumeStatusPublished, 'N') AS published FROM mcu_patient mp LEFT JOIN mcu_patient_resume_status rs ON rs.Mcu_PatientResumeStatusPreregisterID = mp.Mcu_PatientPreregisterID AND rs.Mcu_PatientResumeStatusMcuID = ? WHERE mp.Mcu_PatientMcuID = ? AND mp.Mcu_PatientIsActive = 'Y' ORDER BY rs.Mcu_PatientResumeStatusValidated DESC, mp.Mcu_PatientName ASC `, mcuID, mcuID) if err != nil { return nil, err } defer rows.Close() var result []ProgressRow for rows.Next() { var r ProgressRow if err := rows.Scan(&r.PreregisterID, &r.NIP, &r.Name, &r.Posisi, &r.ResumeStatus, &r.Validated, &r.Published); err != nil { continue } result = append(result, r) } return result, nil } func BuildProgressSummary(rows []ProgressRow) ProgressSummary { s := ProgressSummary{Total: len(rows)} for _, r := range rows { if r.Validated == "Y" { s.Validated++ } if r.Published == "Y" { s.Published++ } } return s } func FilterProgressRows(rows []ProgressRow, search, status string) []ProgressRow { search = strings.ToLower(strings.TrimSpace(search)) status = strings.TrimSpace(status) if search == "" && status == "" { return rows } out := make([]ProgressRow, 0, len(rows)) for _, r := range rows { switch status { case "validated": if r.Validated != "Y" { continue } case "published": if r.Published != "Y" { continue } case "not_validated": if r.Validated == "Y" { continue } case "not_published": if r.Published == "Y" { continue } } if search != "" { hay := strings.ToLower(r.Name + " " + r.NIP + " " + r.Posisi) if !strings.Contains(hay, search) { continue } } out = append(out, r) } return out } func Pct(num, total int) int { if total == 0 { return 0 } return num * 100 / total }