package repository import ( "context" "database/sql" ) // LaporanMCUParams is the date range used by docs/lap_mcu.php. The bounds are // deliberately second-based because the legacy report queried // "tanggal 00:00:01" through "tanggal2 23:59:59". type LaporanMCUParams struct { Tanggal string Tanggal2 string } // LaporanMCURow contains the columns that the legacy Excel report writes. // Nullable values remain pointers so an absent HIS record is represented as // null by the API, while values for which the PHP report supplied a fallback // are always non-null. type LaporanMCURow struct { No int `json:"No"` RegID *string `json:"RegID"` MEDRECID *string `json:"MEDRECID"` NamaPasien *string `json:"NamaPasien"` JenisKelamin *string `json:"JenisKelamin"` TanggalLahir *string `json:"TanggalLahir"` Umur *int64 `json:"Umur"` TanggalMCU *string `json:"TanggalMCU"` NamaPenanggung *string `json:"NamaPenanggung"` DokterMCU *string `json:"DokterMCU"` InstansiKerja *string `json:"InstansiKerja"` TinggiBadan *string `json:"TinggiBadan"` BeratBadan *string `json:"BeratBadan"` TekananDarah *string `json:"TekananDarah"` Nadi *string `json:"Nadi"` Suhu *string `json:"Suhu"` Pernafasan *string `json:"Pernafasan"` Diabetes *string `json:"Diabetes"` Hipertensi *string `json:"Hipertensi"` Dyslipidemia *string `json:"Dyslipidemia"` Jantung *string `json:"Jantung"` Stroke *string `json:"Stroke"` Asma *string `json:"Asma"` Paru *string `json:"Paru"` RiwayatCidera *string `json:"RiwayatCidera"` RiwayatRawatInap *string `json:"RiwayatRawatInap"` RiwayatOperasi *string `json:"RiwayatOperasi"` LainLain *string `json:"LainLain"` DiabetesKeluarga *string `json:"DiabetesKeluarga"` HipertensiKeluarga *string `json:"HipertensiKeluarga"` DyslipidemiaKeluarga *string `json:"DyslipidemiaKeluarga"` JantungKeluarga *string `json:"JantungKeluarga"` StrokeKeluarga *string `json:"StrokeKeluarga"` AsmaKeluarga *string `json:"AsmaKeluarga"` ParuKeluarga *string `json:"ParuKeluarga"` RiwayatCideraKeluarga *string `json:"RiwayatCideraKeluarga"` RiwayatRawatInapKeluarga *string `json:"RiwayatRawatInapKeluarga"` RiwayatOperasiKeluarga *string `json:"RiwayatOperasiKeluarga"` LainLainKeluarga *string `json:"LainLainKeluarga"` AlergiObat *string `json:"AlergiObat"` AlergiMakanan *string `json:"AlergiMakanan"` AlergiLain *string `json:"AlergiLain"` Merokok *string `json:"Merokok"` Alkohol *string `json:"Alkohol"` Olahraga *string `json:"Olahraga"` KeadaanUmum *string `json:"KeadaanUmum"` KeadaanSakit *string `json:"KeadaanSakit"` StatusGizi *string `json:"StatusGizi"` Kesadaran *string `json:"Kesadaran"` ColourBlindness *string `json:"ColourBlindness"` VisusDekat *string `json:"VisusDekat"` KelainananMataLain *string `json:"KelainananMataLain"` Faring *string `json:"Faring"` Tonsil *string `json:"Tonsil"` MulutLainLain *string `json:"MulutLainLain"` KelainanGigi *string `json:"KelainanGigi"` ParuLain *string `json:"ParuLain"` JantungLain *string `json:"JantungLain"` Hernia *string `json:"Hernia"` KeluhanUtama *string `json:"KeluhanUtama"` PenyakitSekarang *string `json:"PenyakitSekarang"` PenyakitDahulu *string `json:"PenyakitDahulu"` ECG *string `json:"ECG"` Audiometri *string `json:"Audiometri"` Spirometri *string `json:"Spirometri"` PemeriksaanLainLain *string `json:"PemeriksaanLainLain"` SaranKesehatanKerja *string `json:"SaranKesehatanKerja"` Kebisingan *string `json:"Kebisingan"` SuhuPanas *string `json:"SuhuPanas"` SuhuDingin *string `json:"SuhuDingin"` RadiasiBukanPengion *string `json:"RadiasiBukanPengion"` RadiasiPengion *string `json:"RadiasiPengion"` GetaranLokal *string `json:"GetaranLokal"` GetaranSeluruhTubuh *string `json:"GetaranSeluruhTubuh"` Ketinggian *string `json:"Ketinggian"` LainLainAkibatKerja *string `json:"LainLainAkibatKerja"` DebuOrganik *string `json:"DebuOrganik"` DebuAnorganik *string `json:"DebuAnorganik"` Asap *string `json:"Asap"` LogamBerat *string `json:"LogamBerat"` PelarutOrganik *string `json:"PelarutOrganik"` IritanAsam *string `json:"IritanAsam"` IritanBasa *string `json:"IritanBasa"` CairanPembersih *string `json:"CairanPembersih"` Pestisida *string `json:"Pestisida"` UapLogam *string `json:"UapLogam"` BahayaKimiaLain *string `json:"BahayaKimiaLain"` Bakteri *string `json:"Bakteri"` CairanTubuh *string `json:"CairanTubuh"` Serangga *string `json:"Serangga"` Limbah *string `json:"Limbah"` BiologiLain *string `json:"BiologiLain"` Overload *string `json:"Overload"` Mismatch *string `json:"Mismatch"` KetidakJelasan *string `json:"KetidakJelasan"` HambatanJenjangKarir *string `json:"HambatanJenjangKarir"` KerjaShift *string `json:"KerjaShift"` KonflikTeman *string `json:"KonflikTeman"` KonflikKeluarga *string `json:"KonflikKeluarga"` PsikologisLain *string `json:"PsikologisLain"` TanganBergerakUlang *string `json:"TanganBergerakUlang"` AngkatBerat *string `json:"AngkatBerat"` DudukLama *string `json:"DudukLama"` BerdiriLama *string `json:"BerdiriLama"` PosisiTubuhTidakErgonomis *string `json:"PosisiTubuhTidakErgonomis"` PencahayaanTidakSesuai *string `json:"PencahayaanTidakSesuai"` LihatMonitorLama *string `json:"LihatMonitorLama"` ErgonomisLain *string `json:"ErgonomisLain"` VisusJauhTanpaKoreksiVOD *string `json:"VisusJauhTanpaKoreksiVOD"` VisusJauhTanpaKoreksiVOS *string `json:"VisusJauhTanpaKoreksiVOS"` VisusJauhDenganKoreksiVOD *string `json:"VisusJauhDenganKoreksiVOD"` VisusJauhDenganKoreksiVOS *string `json:"VisusJauhDenganKoreksiVOS"` Pekerjaan *string `json:"Pekerjaan"` DokterPemeriksa *string `json:"DokterPemeriksa"` } func (r MySQLLayananRepository) ListLaporanMCU(ctx context.Context, params LaporanMCUParams) ([]LaporanMCURow, error) { rows, err := r.db.QueryContext(ctx, laporanMCUQuery, params.Tanggal+" 00:00:01", params.Tanggal2+" 23:59:59") if err != nil { return nil, err } defer rows.Close() result := make([]LaporanMCURow, 0) for rows.Next() { row, err := scanLaporanMCURow(rows) if err != nil { return nil, err } row.No = len(result) + 1 result = append(result, row) } if err := rows.Err(); err != nil { return nil, err } return result, nil } const laporanMCUQuery = ` SELECT r.RegID, r.MEDRECID, r.Nama, CASE WHEN m.Kelamin = 'L' THEN 'Laki - Laki' ELSE 'Perempuan' END, DATE_FORMAT(m.TanggalLahir, '%Y-%m-%d'), TIMESTAMPDIFF(YEAR, m.TanggalLahir, CURDATE()), DATE_FORMAT(r.Tanggal, '%Y-%m-%d %H:%i:%s'), COALESCE(NULLIF(p.Nama, ''), 'UMUM'), d.Nama, pm.DepartemenKerja, rd.TinggiBadan, rd.BeratBadan, tv.Tekanandarah, tv.Nadi, tv.Suhu, tv.Pernafasan, COALESCE(NULLIF(rpd.DiabetesDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.HipertensiDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.KelebihanLemakDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.JantungDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.StrokeDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.AsmaDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.ParuDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.CideraDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.RawatInapDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.OperasiDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpd.LainLainDahuluAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.DiabetesAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.HypertensiAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.KelebihanLemakAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.JantungAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.StrokeAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.AsmaAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.ParuAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.CideraAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.RawatInapAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.OperasiAda, ''), 'Tidak Ada'), COALESCE(NULLIF(rpk.LainLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(ra.AlergiObatAda, ''), 'Tidak Ada'), COALESCE(NULLIF(ra.AlergiMakananAda, ''), 'Tidak Ada'), COALESCE(NULLIF(ra.AlergiLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(gl.SejakKapanMerokok, ''), 'Tidak Merokok'), COALESCE(NULLIF(gl.SejakKapanAlkohol, ''), 'Tidak Minum ALkohol'), COALESCE(NULLIF(gl.KebiasaanOlahragaAda, ''), 'Tidak Olahraga'), pfu.KeadaanUmum, pfu.KeadaanSakit, pfu.StatusGizi, pfu.Kesadaran, pmata.ColourBlindness, COALESCE(NULLIF(pmata.VisusDekatKelainan, ''), 'Normal'), COALESCE(NULLIF(pmata.MataLainLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(ptg.FaringKelainan, ''), 'Normal'), COALESCE(NULLIF(ptg.TonsilKelainan, ''), 'Tidak Ada'), COALESCE(NULLIF(pmulut.MulutLainLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(pgigi.KelainanGigiAda, ''), 'Tidak Ada'), COALESCE(NULLIF(pparu.ParuLainLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(pjantung.JantungLainLainAda, ''), 'Tidak Ada'), COALESCE(NULLIF(pabd.HerniaAda, ''), 'Tidak Ada'), pm.KeluhanUtamaRingkasan, pm.PenyakitSekarangRingkasan, pm.PenyakitDahuluRingkasan, ph.ECG, ph.Audiometri, ph.Spirometri, pm.PemeriksaanLainLainRingkasan, pm.SaranKesehatanKerjaRingkasan, COALESCE(NULLIF(pak.KebisinganAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.SuhuPanasAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.SuhuDinginAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.RadiasiBukanPengionAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.RadiasiPengionAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.GetaranLokalAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.GetaranSeluruhTubuhAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.KetinggianAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.FisikLainLainAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.DebuOrganikAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.DebuAnorganikAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.AsapAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.LogamBeratAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.PelarutOrganikAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.IritanAsamAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.IritanBasaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.CairanPembersihAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.PestisidaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.UapLogamAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.BahanKimiaBerbahayaLainLainAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.BakteriAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.CairanTubuhAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.SeranggaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.LimbahAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.BiologiLainLainAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.OverLoadKerjaanAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.MismatchKerjaanAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.KetidakjelasanTugasAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.HambatanJenjangKarirAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.KerjaShiftAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.KonflikTemanKerjaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.KonflikKeluargaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.PsikologisLainLainAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.TanganBergerakBerulangAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.AngkatBebanBeratAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.DudukLamaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.BerdiriLamaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.PosisiTubuhTidakErgonomisAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.PencahayaanTidakSesuaiAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.LihatMonitorLamaAda, ''), 'TidakAda'), COALESCE(NULLIF(pak.ErgonomisLainLainAda, ''), 'TidakAda'), pmata.VisusJauhTanpaKoreksiVOD, pmata.VisusJauhTanpaKoreksiVOS, pmata.VisusJauhDenganKoreksiVOD, pmata.VisusJauhDenganKoreksiVOS, m.Pekerjaan, dp.Nama FROM regpas AS r LEFT JOIN medrec AS m ON m.MEDRECID = r.MEDRECID LEFT JOIN pengkajianmcu AS pm ON pm.RegID = r.RegID LEFT JOIN dokter AS d ON d.DokterID = r.DokterID LEFT JOIN dokter AS dp ON dp.DokterID = pm.DokterIDPengkaji LEFT JOIN perusahaan AS p ON p.PerusahaanID = r.AsuransiID LEFT JOIN tandavital_pasien AS tv ON tv.RegID = r.RegID AND tv.TekananDarah NOT LIKE '' LEFT JOIN regpas_detail AS rd ON rd.RegID = r.RegID LEFT JOIN gayahidup AS gl ON gl.RegID = r.RegID LEFT JOIN riwayatpenyakitdahulu AS rpd ON rpd.RegID = r.RegID LEFT JOIN riwayatpenyakitkeluarga AS rpk ON rpk.RegID = r.RegID LEFT JOIN riwayatalergi AS ra ON ra.MEDRECID = r.MEDRECID LEFT JOIN pemeriksaanfisik_umum AS pfu ON pfu.RegID = r.RegID LEFT JOIN pemeriksaanfisik_mata AS pmata ON pmata.RegID = r.RegID LEFT JOIN pemeriksaanfisik_tenggorokan AS ptg ON ptg.RegID = r.RegID LEFT JOIN pemeriksaanfisik_mulut AS pmulut ON pmulut.RegID = r.RegID LEFT JOIN pemeriksaanfisik_gigi AS pgigi ON pgigi.RegID = r.RegID LEFT JOIN pemeriksaanfisik_paru AS pparu ON pparu.RegID = r.RegID LEFT JOIN pemeriksaanfisik_jantung AS pjantung ON pjantung.RegID = r.RegID LEFT JOIN pemeriksaanfisik_abdomen AS pabd ON pabd.RegID = r.RegID LEFT JOIN pemeriksaankhusus AS ph ON ph.RegID = r.RegID LEFT JOIN penyakitakibatkerja AS pak ON pak.RegID = r.RegID WHERE r.Tanggal BETWEEN ? AND ? AND r.JenisRegID = '2' AND r.NA = 'N' ORDER BY r.Tanggal, r.RegID` func scanLaporanMCURow(scanner rowScanner) (LaporanMCURow, error) { var row LaporanMCURow var regID, medrecID, nama, jenisKelamin, tanggalLahir, tanggalMCU, namaPenanggung, dokterMCU, instansiKerja sql.NullString var umur sql.NullInt64 var fields [103]sql.NullString args := []any{ ®ID, &medrecID, &nama, &jenisKelamin, &tanggalLahir, &umur, &tanggalMCU, &namaPenanggung, &dokterMCU, &instansiKerja, } for i := range fields { args = append(args, &fields[i]) } if err := scanner.Scan(args...); err != nil { return LaporanMCURow{}, err } row.RegID = nullStringPtr(regID) row.MEDRECID = nullStringPtr(medrecID) row.NamaPasien = nullStringPtr(nama) row.JenisKelamin = nullStringPtr(jenisKelamin) row.TanggalLahir = nullStringPtr(tanggalLahir) row.Umur = nullInt64Ptr(umur) row.TanggalMCU = nullStringPtr(tanggalMCU) row.NamaPenanggung = nullStringPtr(namaPenanggung) row.DokterMCU = nullStringPtr(dokterMCU) row.InstansiKerja = nullStringPtr(instansiKerja) values := make([]*string, len(fields)) for i := range fields { values[i] = nullStringPtr(fields[i]) } assignLaporanMCUFields(&row, values) return row, nil } func assignLaporanMCUFields(row *LaporanMCURow, v []*string) { // The SELECT order intentionally mirrors the legacy spreadsheet column // order after the ten patient/header columns above. row.TinggiBadan, row.BeratBadan, row.TekananDarah, row.Nadi, row.Suhu, row.Pernafasan = v[0], v[1], v[2], v[3], v[4], v[5] row.Diabetes, row.Hipertensi, row.Dyslipidemia, row.Jantung, row.Stroke, row.Asma, row.Paru, row.RiwayatCidera, row.RiwayatRawatInap, row.RiwayatOperasi, row.LainLain = v[6], v[7], v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15], v[16] row.DiabetesKeluarga, row.HipertensiKeluarga, row.DyslipidemiaKeluarga, row.JantungKeluarga, row.StrokeKeluarga, row.AsmaKeluarga, row.ParuKeluarga, row.RiwayatCideraKeluarga, row.RiwayatRawatInapKeluarga, row.RiwayatOperasiKeluarga, row.LainLainKeluarga = v[17], v[18], v[19], v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27] row.AlergiObat, row.AlergiMakanan, row.AlergiLain, row.Merokok, row.Alkohol, row.Olahraga = v[28], v[29], v[30], v[31], v[32], v[33] row.KeadaanUmum, row.KeadaanSakit, row.StatusGizi, row.Kesadaran, row.ColourBlindness, row.VisusDekat, row.KelainananMataLain = v[34], v[35], v[36], v[37], v[38], v[39], v[40] row.Faring, row.Tonsil, row.MulutLainLain, row.KelainanGigi, row.ParuLain, row.JantungLain, row.Hernia = v[41], v[42], v[43], v[44], v[45], v[46], v[47] row.KeluhanUtama, row.PenyakitSekarang, row.PenyakitDahulu, row.ECG, row.Audiometri, row.Spirometri, row.PemeriksaanLainLain, row.SaranKesehatanKerja = v[48], v[49], v[50], v[51], v[52], v[53], v[54], v[55] row.Kebisingan, row.SuhuPanas, row.SuhuDingin, row.RadiasiBukanPengion, row.RadiasiPengion, row.GetaranLokal, row.GetaranSeluruhTubuh, row.Ketinggian, row.LainLainAkibatKerja, row.DebuOrganik, row.DebuAnorganik, row.Asap, row.LogamBerat, row.PelarutOrganik, row.IritanAsam, row.IritanBasa, row.CairanPembersih, row.Pestisida, row.UapLogam, row.BahayaKimiaLain = v[56], v[57], v[58], v[59], v[60], v[61], v[62], v[63], v[64], v[65], v[66], v[67], v[68], v[69], v[70], v[71], v[72], v[73], v[74], v[75] row.Bakteri, row.CairanTubuh, row.Serangga, row.Limbah, row.BiologiLain, row.Overload, row.Mismatch, row.KetidakJelasan, row.HambatanJenjangKarir, row.KerjaShift, row.KonflikTeman, row.KonflikKeluarga, row.PsikologisLain, row.TanganBergerakUlang, row.AngkatBerat, row.DudukLama, row.BerdiriLama, row.PosisiTubuhTidakErgonomis, row.PencahayaanTidakSesuai, row.LihatMonitorLama, row.ErgonomisLain = v[76], v[77], v[78], v[79], v[80], v[81], v[82], v[83], v[84], v[85], v[86], v[87], v[88], v[89], v[90], v[91], v[92], v[93], v[94], v[95], v[96] row.VisusJauhTanpaKoreksiVOD, row.VisusJauhTanpaKoreksiVOS, row.VisusJauhDenganKoreksiVOD, row.VisusJauhDenganKoreksiVOS, row.Pekerjaan, row.DokterPemeriksa = v[97], v[98], v[99], v[100], v[101], v[102] }