db_smartone = $CI->load->database("default", true); } function clean_mysqli_connection($dbc) { while (mysqli_more_results($dbc)) { if (mysqli_next_result($dbc)) { $result = mysqli_use_result($dbc); if (get_class($result) == 'mysqli_stmt') { mysqli_stmt_free_result($result); } else { unset($result); } } } } // ============================================================ // ENTRY POINT UTAMA (GET) // Parameter : $order_header_id = T_OrderHeaderID // Mengembalikan JSON object berisi semua data fisik yang sudah // diproses, termasuk dukungan bilingual jika // T_OrderHeaderAddOnSecondM_LangID > 0 // ============================================================ function get_data($order_header_id) { $order_header_id = intval($order_header_id); if ($order_header_id <= 0) { echo json_encode(['error' => 'Invalid T_OrderHeaderID']); return; } // -- Cek apakah perlu bilingual -- $sql = "SELECT T_OrderHeaderAddOnSecondM_LangID FROM t_orderheaderaddon WHERE T_OrderHeaderAddOnT_OrderHeaderID = ? AND T_OrderHeaderAddOnIsActive = 'Y' LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); $addon_row = $qry ? $qry->row_array() : []; $second_langid = isset($addon_row['T_OrderHeaderAddOnSecondM_LangID']) ? intval($addon_row['T_OrderHeaderAddOnSecondM_LangID']) : 0; $result = []; $result['tanda_vital'] = $this->get_tanda_vital($order_header_id); $result['status_gizi'] = $this->get_status_gizi($order_header_id); $result['persepsi_warna'] = $this->get_persepsi_warna($order_header_id); $result['visus'] = $this->get_visus($order_header_id); $result['body_fat'] = $this->get_body_fat($order_header_id); if ($second_langid > 0) { $result['tanda_vital_lang2'] = $this->get_tanda_vital($order_header_id, $second_langid); $result['status_gizi_lang2'] = $this->get_status_gizi($order_header_id, $second_langid); $result['persepsi_warna_lang2'] = $this->get_persepsi_warna($order_header_id, $second_langid); $result['visus_lang2'] = $this->get_visus($order_header_id, $second_langid); } $result['second_langid'] = $second_langid; echo json_encode($result); } // ============================================================ // ENTRY POINT UTAMA (SAVE) // Membaca semua row so_resultentry_fisik_umum untuk 1 order, // lalu INSERT ke so_resultentry_fisik_summary (1 tabel). // • tanda_vital → 1 baris per item pengukuran // • template lain → 1 baris per item yang abnormal (dicentang+tidak normal) // // Idempotent: hapus dulu data lama (IsActive='Y') sebelum insert. // // @param int $order_header_id T_OrderHeaderID // @param int $user_id M_UserID // @return array ['success'=>bool, 'saved'=>int, 'errors'=>array] // ============================================================ function save_data($order_header_id, $user_id = 0) { $order_header_id = intval($order_header_id); $result = [ 'success' => false, 'saved' => 0, 'errors' => [], ]; if ($order_header_id <= 0) { $result['errors'][] = 'Invalid T_OrderHeaderID'; return $result; } // -- 1. Ambil semua template yang sudah diisi untuk order ini -- $sql = "SELECT srfu.*, ft.FisikTemplateCode, ft.FisikTemplateType, ft.FisikTemplateTableName, ft.FisikTemplateTitle FROM so_resultentry_fisik_umum srfu JOIN fisik_template ft ON srfu.So_ResultEntryFisikUmumFisikTemplateID = ft.FisikTemplateID AND ft.FisikTemplateIsActive = 'Y' WHERE srfu.So_ResultEntryFisikUmumT_OrderHeaderID = ? AND srfu.So_ResultEntryFisikUmumIsActive = 'Y'"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) { $result['errors'][] = 'Query so_resultentry_fisik_umum gagal'; return $result; } $rows = $qry->result_array(); if (count($rows) == 0) { $result['errors'][] = 'Tidak ada data fisik untuk order ini'; return $result; } // -- 2. Hapus data lama (soft-delete dulu, lalu truncate baris lama) -- // Gunakan hard-delete (DELETE) untuk idempotent yang bersih, // karena data lama sudah di-soft-delete saat unval1. $this->db_smartone->query( "DELETE FROM so_resultentry_fisik_summary WHERE So_ResultEntryFisikSummaryT_OrderHeaderID = ?", [$order_header_id] ); $now = date('Y-m-d H:i:s'); // -- 3. Proses tiap template -- foreach ($rows as $row) { $json_str = $row['So_ResultEntryFisikUmumDetails']; $template_id = intval($row['So_ResultEntryFisikUmumFisikTemplateID']); $tmpl_code = $row['FisikTemplateCode']; $tmpl_title = $row['FisikTemplateTitle']; $tmpl_table = $row['FisikTemplateTableName']; $d = json_decode($json_str, true); if (!$d) { $result['errors'][] = "JSON invalid untuk template {$tmpl_code}"; continue; } $type_form = strtoupper($d['type_form'] ?? ''); $is_tanda_vital = ( $tmpl_table === 'tanda_vital' || strtoupper($tmpl_title) === 'TANDA VITAL' || in_array($tmpl_code, ['FI00', 'FI00.TD']) ); if ($is_tanda_vital) { // -- Tanda Vital: 1 baris per item pengukuran -- $tv_items = $this->build_tanda_vital_rows($d); foreach ($tv_items as $tv) { $ok = $this->insert_summary_row( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $tv['id_code'], $tv['label'], $tv['label'], $tv['value'], $tv['value2'], $tv['value_numeric'], $tv['value2_numeric'], null, null, null, 'tanda_vital', $user_id, $now ); if ($ok) $result['saved']++; } continue; } // -- Template lain: simpan semua item yang dicentang -- // Aturan: // • is_normal='Y' + chx=true → type='normal' // • is_normal='N' + chx=true → type='kelainan' // • XXV chx_y=true → type='normal' // • XXV chx_x=true → type='kelainan' // • Riwayat/K3: chx=true → type='kelainan' // • Riwayat/K3: tidak ada yg dicentang → 1 baris 'Tidak Ada' type='normal' $details = $d['details'] ?? []; $tmpl_type = strtoupper($d['type_form'] ?? ''); $is_riwayat = in_array($tmpl_type, ['XV', 'XVS', 'XO', 'XD', 'XVS-LXX']) && !isset($d['flag_normal']) // Fisik punya flag_normal, Riwayat tidak && ($tmpl_type !== 'XV' || !$this->has_is_normal_field($details)); // Lebih tepat: Riwayat tidak punya is_normal di items-nya $is_riwayat_or_k3 = $this->is_riwayat_or_k3_template($details, $tmpl_type); $any_checked = false; $saved_in_tmpl = 0; foreach ($details as $item) { if (isset($item['details']) && is_array($item['details'])) { $segment = $item['name'] ?? ($item['segment_name'] ?? null); foreach ($item['details'] as $sub_item) { $sub_item['_segment'] = $segment; $saved = $this->save_item_by_rule( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $tmpl_type, $tmpl_title, $sub_item, $user_id, $now ); if ($saved) { $result['saved']++; $saved_in_tmpl++; $any_checked = true; } } } else { $saved = $this->save_item_by_rule( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $tmpl_type, $tmpl_title, $item, $user_id, $now ); if ($saved) { $result['saved']++; $saved_in_tmpl++; $any_checked = true; } } } // -- Jika Riwayat/K3 tidak ada yang dicentang → simpan 'Tidak Ada' -- if ($is_riwayat_or_k3 && !$any_checked) { $ok = $this->insert_summary_row( $order_header_id, $template_id, $tmpl_code, $tmpl_table, 'tidak_ada', 'Tidak Ada', 'Tidak Ada', null, null, null, null, null, null, null, 'normal', $user_id, $now ); if ($ok) $result['saved']++; } } $result['success'] = true; return $result; } // ============================================================ // Helper: cek apakah template ini Riwayat atau K3 // (bedanya dengan Fisik: items tidak punya is_normal) // ============================================================ private function is_riwayat_or_k3_template($details, $type_form) { if ($type_form === 'XVV') return true; // K3 selalu XVV // Cek apakah ada item dengan is_normal → berarti Fisik, bukan Riwayat foreach ($details as $item) { if (isset($item['is_normal'])) return false; if (isset($item['details'])) { foreach ($item['details'] as $sub) { if (isset($sub['is_normal'])) return false; } } } return true; // tidak ada is_normal → Riwayat } // ============================================================ // Helper: cek apakah detail punya field is_normal (Fisik) // ============================================================ private function has_is_normal_field($details) { foreach ($details as $item) { if (isset($item['is_normal'])) return true; if (isset($item['details'])) { foreach ($item['details'] as $sub) { if (isset($sub['is_normal'])) return true; } } } return false; } // ============================================================ // SAVE ITEM BY RULE // Tentukan summary_type berdasarkan is_normal + chx // Hanya simpan jika item dicentang (chx=true / chx_x / chx_y) // $tmpl_title dipakai untuk LabelDisplay: "JantungTitle : segment" // ============================================================ private function save_item_by_rule( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $type_form, $tmpl_title, $item, $user_id, $now ) { $chx = !empty($item['chx']) || $item['chx'] === 1 || $item['chx'] === '1' || $item['chx'] === true; $chx_x = !empty($item['chx_x']) || $item['chx_x'] === 1 || $item['chx_x'] === '1' || $item['chx_x'] === true; $chx_y = !empty($item['chx_y']) || $item['chx_y'] === 1 || $item['chx_y'] === '1' || $item['chx_y'] === true; $is_normal_field = isset($item['is_normal']) ? strtoupper($item['is_normal']) : null; $summary_type = null; // Skip tipe yang tidak masuk summary $skip_types = ['VXX+', 'VXX', 'V', 'T', 'XXVWL']; if (in_array($type_form, $skip_types)) return false; if ($type_form === 'XXV') { // chx_y = Normal, chx_x = Tidak Normal if ($chx_y) $summary_type = 'normal'; elseif ($chx_x) $summary_type = 'kelainan'; else return false; } elseif ($type_form === 'XVV') { // K3: chx = ada paparan = kelainan if (!$chx) return false; $summary_type = 'kelainan'; } elseif ($type_form === 'TOOTH') { if (!$chx) return false; $summary_type = 'kelainan'; } else { // XV, XVS, XVS-LXX, XO, XD, X, Riwayat ... if (!$chx) return false; if ($is_normal_field === 'Y') $summary_type = 'normal'; elseif ($is_normal_field === 'N') $summary_type = 'kelainan'; else $summary_type = 'kelainan'; // Riwayat (tidak ada is_normal) → kelainan } $id_code = $item['id_code'] ?? ''; $label = $item['label'] ?? ''; $value = $item['value'] ?? null; $segment = $item['segment_name'] ?? ($item['_segment'] ?? null); $value_sumber = $item['value_sumber'] ?? null; $value_lama = $item['value_lama'] ?? null; // -- Bangun LabelDisplay & Value -- // // Pola universal: // Fisik ber-segment → "Jantung : Apex" // Fisik tanpa segment → "Deformitas" (label saja) // XO (Penyakit Keluarga) → "Riwayat Penyakit Keluarga : Diabetes Melitus" // Value = "Ayah, Ibu" (dari options.selected) // XD (Imunisasi) → "Riwayat Imunisasi : Hepatitis A" // XVS Riwayat ber-segment → "Riwayat Kebiasaan Hidup : Minum alkohol" // XV Riwayat tanpa segment → "Riwayat Penyakit : Gastritis (maag)" // // Cara membedakan Riwayat vs Fisik: is_normal ada → Fisik, tidak ada → Riwayat $title_clean = ucwords(strtolower(trim($tmpl_title))); $is_riwayat_item = ($is_normal_field === null) && !in_array($type_form, ['XXV', 'XVV', 'TOOTH']); if ($type_form === 'XO') { // LabelDisplay = "Riwayat Penyakit Keluarga : Diabetes Melitus" // Value = "Ayah, Ibu" $label_display = $title_clean . ' : ' . $label; if (!empty($item['options'])) { $selected_opts = []; foreach ($item['options'] as $opt) { if (!empty($opt['selected'])) { $selected_opts[] = $opt['label']; } } if (count($selected_opts) > 0) { $value = implode(', ', $selected_opts); } } } elseif ($is_riwayat_item && $segment) { // Riwayat ber-segment: "Riwayat Kebiasaan Hidup : Minum alkohol" $label_display = $title_clean . ' : ' . $segment; } elseif ($is_riwayat_item) { // Riwayat tanpa segment: "Riwayat Penyakit : Gastritis (maag)" $label_display = $title_clean . ' : ' . $label; } elseif ($segment) { // Fisik ber-segment (is_normal ada): "Jantung : Apex" $label_display = $title_clean . ' : ' . $segment; } else { // Fisik tanpa segment: "Deformitas" $label_display = $label; } return $this->insert_summary_row( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $id_code, $label, $label_display, $value, null, null, null, $segment, $value_sumber, $value_lama, $summary_type, $user_id, $now ); } // ============================================================ // BUILD TANDA VITAL ROWS // Dari JSON detail tanda vital, buat array item siap INSERT // id_code: tanda_vital_5 → TD (sistole + diastole) // tanda_vital_6 → Suhu // tanda_vital_1 → Nadi // tanda_vital_2 → Ritme nadi // tanda_vital_3 → Laju nafas // tanda_vital_4 → Pola nafas // ============================================================ private function build_tanda_vital_rows($d) { $rows = []; foreach ($d['details'] as $item) { $code = $item['id_code'] ?? ''; // Tekanan Darah: value_x=sistole, value_y=diastole if ($code === 'tanda_vital_5') { $sistole = $item['value_x'] ?? null; $diastole = $item['value_y'] ?? null; $rows[] = [ 'id_code' => 'tanda_vital_5', 'label' => 'Tekanan Darah', 'value' => $sistole, 'value2' => $diastole, 'value_numeric' => is_numeric($sistole) ? floatval($sistole) : null, 'value2_numeric' => is_numeric($diastole) ? floatval($diastole) : null, ]; } // Suhu: value=angka, chx_x/chx_y → label ket (Febrile/Afebrile) if ($code === 'tanda_vital_6') { $suhu_val = $item['value'] ?? null; if (!empty($item['chx_x'])) { $ket = $item['label_x'] ?? null; } elseif (!empty($item['chx_y'])) { $ket = $item['label_y'] ?? null; } else { $ket = null; } $rows[] = [ 'id_code' => 'tanda_vital_6', 'label' => 'Suhu', 'value' => $ket, 'value2' => $suhu_val, 'value_numeric' => null, 'value2_numeric' => is_numeric($suhu_val) ? floatval($suhu_val) : null, ]; } // Denyut Nadi if ($code === 'tanda_vital_1') { $val = $item['value'] ?? null; $rows[] = [ 'id_code' => 'tanda_vital_1', 'label' => 'Denyut Nadi', 'value' => $val, 'value2' => null, 'value_numeric' => is_numeric($val) ? floatval($val) : null, 'value2_numeric' => null, ]; } // Ritme Nadi: chx_y=Reguler, chx_x=Ireguler if ($code === 'tanda_vital_2') { if (!empty($item['chx_y'])) { $ritme = $item['label_y'] ?? 'Reguler'; } elseif (!empty($item['chx_x'])) { $ritme = $item['label_x'] ?? 'Ireguler'; } else { $ritme = null; } $rows[] = [ 'id_code' => 'tanda_vital_2', 'label' => 'Ritme Nadi', 'value' => $ritme, 'value2' => null, 'value_numeric' => null, 'value2_numeric' => null, ]; } // Laju Pernafasan if ($code === 'tanda_vital_3') { $val = $item['value'] ?? null; $rows[] = [ 'id_code' => 'tanda_vital_3', 'label' => 'Laju Pernafasan', 'value' => $val, 'value2' => null, 'value_numeric' => is_numeric($val) ? floatval($val) : null, 'value2_numeric' => null, ]; } // Pola Nafas if ($code === 'tanda_vital_4') { if (!empty($item['chx_y'])) { $pola = $item['label_y'] ?? 'Normal'; } elseif (!empty($item['chx_x'])) { $pola = $item['label_x'] ?? 'Tidak normal'; } else { $pola = null; } $rows[] = [ 'id_code' => 'tanda_vital_4', 'label' => 'Pola Nafas', 'value' => $pola, 'value2' => null, 'value_numeric' => null, 'value2_numeric' => null, ]; } } return $rows; } // ============================================================ // SAVE KELAINAN ITEM (legacy - masih dipakai oleh is_item_abnormal) // ============================================================ private function save_kelainan_item( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $type_form, $item, $user_id, $now ) { if (!$this->is_item_abnormal($type_form, $item)) { return false; } $id_code = $item['id_code'] ?? ''; $label = $item['label'] ?? ''; $value = $item['value'] ?? null; $segment = $item['segment_name'] ?? ($item['_segment'] ?? null); $value_sumber = $item['value_sumber'] ?? null; $value_lama = $item['value_lama'] ?? null; return $this->insert_summary_row( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $id_code, $label, $value, null, null, null, $segment, $value_sumber, $value_lama, 'kelainan', $user_id, $now ); } // ============================================================ // INSERT KE so_resultentry_fisik_summary // Satu fungsi INSERT untuk semua tipe baris // $label_display = teks siap tampil (Jantung : Apex, DM (Ayah), dst) // ============================================================ private function insert_summary_row( $order_header_id, $template_id, $tmpl_code, $tmpl_table, $id_code, $label, $label_display, $value, $value2, $value_numeric, $value2_numeric, $segment, $value_sumber, $value_lama, $summary_type, $user_id, $now ) { $sql = "INSERT INTO so_resultentry_fisik_summary ( So_ResultEntryFisikSummaryT_OrderHeaderID, So_ResultEntryFisikSummaryFisikTemplateID, So_ResultEntryFisikSummaryFisikTemplateCode, So_ResultEntryFisikSummaryTableName, So_ResultEntryFisikSummaryIdCode, So_ResultEntryFisikSummaryLabel, So_ResultEntryFisikSummaryLabelDisplay, So_ResultEntryFisikSummarySegment, So_ResultEntryFisikSummaryValue, So_ResultEntryFisikSummaryValue2, So_ResultEntryFisikSummaryValueNumeric, So_ResultEntryFisikSummaryValue2Numeric, So_ResultEntryFisikSummaryValueSumber, So_ResultEntryFisikSummaryValueLama, So_ResultEntryFisikSummaryType, So_ResultEntryFisikSummaryIsActive, So_ResultEntryFisikSummaryCreated, So_ResultEntryFisikSummaryCreatedUserID, So_ResultEntryFisikSummaryLastUpdated, So_ResultEntryFisikSummaryLastUpdatedUserID ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,'Y',?,?,?,?)"; $qry = $this->db_smartone->query($sql, [ $order_header_id, $template_id, $tmpl_code, $tmpl_table, $id_code, $label, $label_display, $segment, $value, $value2, $value_numeric, $value2_numeric, $value_sumber, $value_lama, $summary_type, $now, $user_id, $now, $user_id, ]); return (bool)$qry; } // ============================================================ // IS ITEM ABNORMAL? // Lihat comment lengkap di versi sebelumnya // ============================================================ private function is_item_abnormal($type_form, $item) { $chx = !empty($item['chx']) || $item['chx'] === 1 || $item['chx'] === '1' || $item['chx'] === true; $chx_x = !empty($item['chx_x']) || $item['chx_x'] === 1 || $item['chx_x'] === '1' || $item['chx_x'] === true; $is_normal = isset($item['is_normal']) ? strtoupper($item['is_normal']) : null; $skip_types = ['VXX+', 'VXX', 'V', 'T', 'XXVWL', 'XVS3R']; if (in_array($type_form, $skip_types)) return false; if ($type_form === 'XXV') return $chx_x; if ($type_form === 'XVV') return $chx; if ($type_form === 'TOOTH') return $chx; if (in_array($type_form, ['XV', 'XVS', 'XVS-LXX', 'XD', 'XO'])) { if ($is_normal !== null) { return ($chx && $is_normal === 'N'); } return $chx; } if ($type_form === 'X') return $chx; return $chx; } // ============================================================ // GET TANDA VITAL // Baca dari so_resultentry_fisik_summary (type='tanda_vital') // Fallback ke so_resultentry_fisik_umum jika summary belum ada // ============================================================ function get_tanda_vital($order_header_id, $langid = 1) { $empty = [ 'td_sistole' => 'NaN', 'td_diastole' => 'NaN', 'td_nilai' => 'NaN', 'td_standart' => 'NaN', 'suhu' => 'NaN', 'suhu_ket' => 'NaN', 'nadi' => 'NaN', 'ritme_nadi' => 'NaN', 'laju_nafas' => 'NaN', 'pola_nafas' => 'NaN', ]; // -- Coba baca dari summary dulu (sudah diproses) -- $sql = "SELECT So_ResultEntryFisikSummaryIdCode as id_code, So_ResultEntryFisikSummaryValue as val, So_ResultEntryFisikSummaryValue2 as val2 FROM so_resultentry_fisik_summary WHERE So_ResultEntryFisikSummaryT_OrderHeaderID = ? AND So_ResultEntryFisikSummaryType = 'tanda_vital' AND So_ResultEntryFisikSummaryIsActive = 'Y'"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if ($qry && count($qry->result_array()) > 0) { $out = $empty; foreach ($qry->result_array() as $r) { switch ($r['id_code']) { case 'tanda_vital_5': $out['td_sistole'] = $r['val'] ?? ''; $out['td_diastole'] = $r['val2'] ?? ''; break; case 'tanda_vital_6': $out['suhu_ket'] = $this->translate_word($r['val'] ?? '', $langid); $out['suhu'] = $r['val2'] ?? ''; break; case 'tanda_vital_1': $out['nadi'] = ($r['val'] !== null) ? $r['val'] . ' ' . $this->translate_word('x/menit', $langid) : ''; break; case 'tanda_vital_2': $out['ritme_nadi'] = $this->translate_word($r['val'] ?? '', $langid); break; case 'tanda_vital_3': $out['laju_nafas'] = ($r['val'] !== null) ? $r['val'] . ' ' . $this->translate_word('x/menit', $langid) : ''; break; case 'tanda_vital_4': $out['pola_nafas'] = $this->translate_word($r['val'] ?? '', $langid); break; } } return $out; } // -- Fallback: baca dari so_resultentry_fisik_umum (JSON) -- $table = ($langid == 2) ? 'so_resultentry_fisik_umum_eng' : 'so_resultentry_fisik_umum'; $sql = "SELECT * FROM {$table} JOIN fisik_template ON So_ResultEntryFisikUmumFisikTemplateID = FisikTemplateID AND FisikTemplateIsActive = 'Y' AND FisikTemplateTitle = 'TANDA VITAL' WHERE So_ResultEntryFisikUmumT_OrderHeaderID = ? AND So_ResultEntryFisikUmumIsActive = 'Y' LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) return $empty; $rows = $qry->result_array(); if (count($rows) == 0) return $empty; $d = json_decode($rows[0]['So_ResultEntryFisikUmumDetails'], true); if (!$d || $d['title'] != 'TANDA VITAL') return $empty; $out = $empty; foreach ($d['details'] as $item) { $code = $item['id_code'] ?? ''; if ($code === 'tanda_vital_5') { $out['td_sistole'] = $item['value_x'] ?? ''; $out['td_diastole'] = $item['value_y'] ?? ''; $out['td_nilai'] = $item['value'] ?? ''; $out['td_standart'] = $item['standart'] ?? ''; } if ($code === 'tanda_vital_6') { $out['suhu'] = $item['value'] ?? ''; if (!empty($item['chx_x'])) $out['suhu_ket'] = $this->translate_word($item['label_x'] ?? '', $langid); elseif (!empty($item['chx_y'])) $out['suhu_ket'] = $this->translate_word($item['label_y'] ?? '', $langid); } if ($code === 'tanda_vital_1') { $v = $item['value'] ?? ''; $out['nadi'] = $v !== '' ? $v . ' ' . $this->translate_word('x/menit', $langid) : ''; } if ($code === 'tanda_vital_2') { if (!empty($item['chx_y'])) $out['ritme_nadi'] = $this->translate_word($item['label_y'] ?? 'Reguler', $langid); elseif (!empty($item['chx_x'])) $out['ritme_nadi'] = $this->translate_word($item['label_x'] ?? 'Ireguler', $langid); } if ($code === 'tanda_vital_3') { $v = $item['value'] ?? ''; $out['laju_nafas'] = $v !== '' ? $v . ' ' . $this->translate_word('x/menit', $langid) : ''; } if ($code === 'tanda_vital_4') { if (!empty($item['chx_y'])) $out['pola_nafas'] = $this->translate_word($item['label_y'] ?? 'Normal', $langid); elseif (!empty($item['chx_x'])) $out['pola_nafas'] = $this->translate_word($item['label_x'] ?? 'Tidak normal', $langid); } } return $out; } // ============================================================ // STATUS GIZI // ============================================================ function get_status_gizi($order_header_id, $langid = 1) { $empty = [ 'bb' => 'NaN', 'tb' => 'NaN', 'body_fat' => 'NaN', 'bmi' => 'NaN', 'bmi_classification' => 'NaN', 'bmi_standard' => 'NaN', ]; $sql = "SELECT * FROM t_samplingso_additional_fisik_bbtb WHERE T_SamplingAdditionalFisikBBTBT_OrderHeaderID = ? LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) return $empty; $row = $qry->row_array(); if (!$row) return $empty; $bb = $row['T_SamplingAdditionalFisikBBTBValueBB']; $tb = $row['T_SamplingAdditionalFisikBBTBValueTB']; $standart_bmi = $row['T_SamplingAdditionalFisikBBTBStandart']; $bodyfat_raw = $row['T_SamplingAdditionalFisikBBTBBodyFat']; if (intval($bb) == 0 && intval($tb) == 0) return $empty; $bodyfat = ($bodyfat_raw == -1) ? $this->translate_word('Tidak dilakukan', $langid) : $bodyfat_raw; $get_bmi = $this->hitung_bmi($bb, $tb, $standart_bmi); $bmi_class = $this->translate_word($get_bmi['class'], $langid); return [ 'bb' => $bb, 'tb' => $tb, 'body_fat' => $bodyfat, 'bmi' => $get_bmi['bmi'], 'bmi_classification' => $bmi_class, 'bmi_standard' => ucwords(str_replace('_', ' ', $standart_bmi)), ]; } // ============================================================ // PERSEPSI WARNA // ============================================================ function get_persepsi_warna($order_header_id, $langid = 1) { $empty = ['result' => 'NaN', 'angka' => '']; $sql = "SELECT T_OrderDetailID FROM t_orderdetail WHERE T_OrderDetailT_OrderHeaderID = ? AND T_OrderDetailT_TestCode = '40111200' AND T_OrderDetailIsActive = 'Y' LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry || count($qry->result_array()) == 0) return $empty; $sql = "SELECT IFNULL(T_SamplingAdditionalFisikBWPWValue,'Z') as result, IFNULL(T_SamplingAdditionalFisikBWPWVAngka,'') as angka FROM t_samplingso_additional_fisik_bw WHERE T_SamplingAdditionalFisikBWT_OrderHeaderID = ? LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) return $empty; $row = $qry->row_array(); if (!$row) return $empty; if ($row['result'] == 'BW') $result_text = 'Red Green Deficiency'; elseif ($row['result'] == 'N') $result_text = 'Normal'; elseif ($row['result'] == 'X') $result_text = $this->translate_word('Tidak dilakukan', $langid); else $result_text = $this->translate_word('Bahan Belum', $langid); return ['result' => $result_text, 'angka' => $row['angka']]; } // ============================================================ // VISUS // ============================================================ function get_visus($order_header_id, $langid = 1) { $empty = [ 'visus_kanan' => 'NaN', 'visus_kiri' => 'NaN', 'tk_od' => 'NaN', 'tk_os' => 'NaN', 'dk_od' => 'NaN', 'dk_os' => 'NaN', 'od_sph' => '-', 'od_cyl' => '-', 'od_x' => '-', 'os_sph' => '-', 'os_cyl' => '-', 'os_x' => '-', 'add' => '-', 'kelainan_kanan' => '', 'kelainan_kiri' => '', ]; $sql = "SELECT T_OrderDetailID FROM t_orderdetail WHERE T_OrderDetailT_OrderHeaderID = ? AND T_OrderDetailT_TestCode = '40111000' AND T_OrderDetailIsActive = 'Y' LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry || count($qry->result_array()) == 0) return $empty; $sql = "SELECT *, IFNULL(T_SamplingAdditionalFisikVisusID, 0) as visus_id FROM t_samplingso_additional_fisik_visus WHERE T_SamplingAdditionalFisikVisusT_OrderHeaderID = ? LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) return $empty; $row = $qry->row_array(); if (!$row || intval($row['visus_id']) == 0) { return array_merge($empty, [ 'visus_kanan' => $this->translate_word('Bahan belum', $langid), 'visus_kiri' => $this->translate_word('Bahan belum', $langid), ]); } $normal = ['20/20', '20/25', '6/6', '6/7.5', '6/7,5']; $tk_od = $row['T_SamplingAdditionalFisikVisusTKODV']; $tk_os = $row['T_SamplingAdditionalFisikVisusTKOSV']; $dk_od = $row['T_SamplingAdditionalFisikVisusDKODV']; $dk_os = $row['T_SamplingAdditionalFisikVisusDKOSV']; $od_sph = $row['T_SamplingAdditionalFisikVisusODSPH']; $od_cyl = $row['T_SamplingAdditionalFisikVisusODCYL']; $od_x = $row['T_SamplingAdditionalFisikVisusODX']; $os_sph = trim($row['T_SamplingAdditionalFisikVisusOSSPH']); $os_cyl = $row['T_SamplingAdditionalFisikVisusOSCYL']; $os_x = $row['T_SamplingAdditionalFisikVisusOSX']; $od_add = $row['T_SamplingAdditionalFisikVisusADD']; $is_valid = function ($v) { $v = trim($v); return $v !== '' && $v !== '-' && $v !== '--' && $v !== '/-' && $v !== '/' && $v !== '-/' && strtolower($v) !== 'plano' && strtolower($v) !== 'tidak terkoreksi' && strtolower($v) !== 'tidak dapat dinilai'; }; $kelainan_kanan = ''; if ($is_valid($od_sph)) $kelainan_kanan .= $od_sph . ' (' . $this->translate_word('Miopia', $langid) . ')'; if ($is_valid($od_cyl)) { if ($kelainan_kanan != '') $kelainan_kanan .= ', '; $kelainan_kanan .= 'Cyl ' . $od_cyl; $kelainan_kanan .= $is_valid($od_x) ? ' axis ' . $od_x . ' (' . $this->translate_word('Astigmatismus', $langid) . ')' : ' (' . $this->translate_word('Astigmatismus', $langid) . ')'; } if ($is_valid($od_add)) { if ($kelainan_kanan != '') $kelainan_kanan .= ', '; $kelainan_kanan .= $od_add . ' (' . $this->translate_word('Presbiopia', $langid) . ')'; } $kelainan_kiri = ''; if ($is_valid($os_sph)) $kelainan_kiri .= $os_sph . ' (' . $this->translate_word('Miopia', $langid) . ')'; if ($is_valid($os_cyl)) { if ($kelainan_kiri != '') $kelainan_kiri .= ', '; $kelainan_kiri .= 'Cyl ' . $os_cyl; $kelainan_kiri .= $is_valid($os_x) ? ' axis ' . $os_x . ' (' . $this->translate_word('Astigmatismus', $langid) . ')' : ' (' . $this->translate_word('Astigmatismus', $langid) . ')'; } if ($is_valid($od_add)) { if ($kelainan_kiri != '') $kelainan_kiri .= ', '; $kelainan_kiri .= $od_add . ' (' . $this->translate_word('Presbiopia', $langid) . ')'; } // Teks ringkas kanan if ($tk_od == 'OFF' && $dk_od == 'OFF') { $visus_kanan = $kelainan_kanan ?: 'Normal'; } else { $normal_kanan = (in_array($tk_od, $normal) || in_array($dk_od, $normal)) ? '(Normal)' : ''; $v_od = ($dk_od != '' && $dk_od != '-' && $dk_od != 'OFF') ? $dk_od : (($tk_od != '' && $tk_od != '-' && $tk_od != 'OFF') ? $tk_od : '20/20'); $st_od = ($dk_od != '' && $dk_od != '-' && $dk_od != 'OFF') ? $this->translate_word('dengan kacamata', $langid) : $this->translate_word('tanpa kacamata', $langid); if (!in_array($v_od, $normal) && $kelainan_kanan == '') $kelainan_kanan = $this->translate_word('Miopia', $langid); $pre = trim($v_od . ' ' . strtolower($st_od) . ' ' . $normal_kanan); $visus_kanan = $kelainan_kanan == '' ? $pre : $pre . '; ' . $kelainan_kanan; } // Teks ringkas kiri if ($tk_os == 'OFF' && $dk_os == 'OFF') { $visus_kiri = $kelainan_kiri ?: 'Normal'; } else { $normal_kiri = (in_array($tk_os, $normal) || in_array($dk_os, $normal)) ? '(Normal)' : ''; $v_os = ($dk_os != '' && $dk_os != '-' && $dk_os != 'OFF') ? $dk_os : (($tk_os != '' && $tk_os != '-' && $tk_os != 'OFF') ? $tk_os : '20/20'); $st_os = ($dk_os != '' && $dk_os != '-' && $dk_os != 'OFF') ? $this->translate_word('dengan kacamata', $langid) : $this->translate_word('tanpa kacamata', $langid); if (!in_array($v_os, $normal) && $kelainan_kiri == '') $kelainan_kiri = $this->translate_word('Miopia', $langid); $pre = trim($v_os . ' ' . strtolower($st_os) . ' ' . $normal_kiri); $visus_kiri = $kelainan_kiri == '' ? $pre : $pre . '; ' . $kelainan_kiri; } return [ 'visus_kanan' => $visus_kanan, 'visus_kiri' => $visus_kiri, 'tk_od' => $tk_od ?: '-', 'tk_os' => $tk_os ?: '-', 'dk_od' => $dk_od ?: '-', 'dk_os' => $dk_os ?: '-', 'od_sph' => $od_sph ?: '-', 'od_cyl' => $od_cyl ?: '-', 'od_x' => $od_x ?: '-', 'os_sph' => $os_sph ?: '-', 'os_cyl' => $os_cyl ?: '-', 'os_x' => $os_x ?: '-', 'add' => $od_add ?: '-', 'kelainan_kanan' => $kelainan_kanan, 'kelainan_kiri' => $kelainan_kiri, ]; } // ============================================================ // BODY FAT // ============================================================ function get_body_fat($order_header_id, $langid = 1) { $sql = "SELECT T_SamplingAdditionalFisikBBTBBodyFat as body_fat FROM t_samplingso_additional_fisik_bbtb WHERE T_SamplingAdditionalFisikBBTBT_OrderHeaderID = ? LIMIT 1"; $qry = $this->db_smartone->query($sql, [$order_header_id]); if (!$qry) return ['body_fat' => 'NaN', 'body_fat_display' => 'NaN']; $row = $qry->row_array(); if (!$row) return ['body_fat' => 'NaN', 'body_fat_display' => 'NaN']; $val = $row['body_fat']; if ($val === null || $val === '') return ['body_fat' => 'NaN', 'body_fat_display' => 'NaN']; if ($val == -1) return ['body_fat' => 'NaN', 'body_fat_display' => $this->translate_word('Tidak dilakukan', $langid)]; return ['body_fat' => $val, 'body_fat_display' => $val . '%']; } // ============================================================ // HITUNG BMI // ============================================================ function hitung_bmi($bb, $tb, $standart_bmi) { if (floatval($tb) <= 0) return ['bmi' => 'NaN', 'class' => 'Undefined']; $tb_m = floatval($tb) / 100; $bmi = floatval($bb) / ($tb_m * $tb_m); $bmi_v = number_format($bmi, 2); $class = 'Undefined'; if ($standart_bmi === 'asia_pacific') { if ($bmi_v < 18.5) $class = 'Underweight'; if ($bmi_v >= 18.5 && $bmi_v < 23) $class = 'Normal'; if ($bmi_v >= 23 && $bmi_v < 25) $class = 'Overweight'; if ($bmi_v >= 25 && $bmi_v < 30) $class = 'Obese I'; if ($bmi_v >= 30) $class = 'Obese II'; } if ($standart_bmi === 'who') { if ($bmi_v < 18.5) $class = 'Underweight'; if ($bmi_v >= 18.5 && $bmi_v < 25) $class = 'Normal'; if ($bmi_v >= 25 && $bmi_v < 30) $class = 'Overweight'; if ($bmi_v >= 30) $class = 'Obese'; } if ($standart_bmi === 'kemenkes') { if ($bmi_v < 18.5) $class = 'Underweight'; if ($bmi_v >= 18.5 && $bmi_v < 25.1) $class = 'Normal'; if ($bmi_v >= 25.1 && $bmi_v < 27) $class = 'Overweight'; if ($bmi_v >= 27) $class = 'Obese'; } return ['bmi' => $bmi_v, 'class' => $class]; } // ============================================================ // TRANSLATE // ============================================================ function translate_word($word, $langid = 1) { if ($langid == 1) return $word; $sql = "SELECT Translate_WordTo FROM translate_word WHERE Translate_WordIsActive = 'Y' AND Translate_WordFrom = '{$word}' LIMIT 1"; $qry = $this->db_smartone->query($sql); if (!$qry) return $word; $rows = $qry->result_array(); return (count($rows) > 0) ? $rows[0]['Translate_WordTo'] : $word; } function translate_sentence($sentence, $langid = 1) { $words = preg_split('/[\s-]+/', $sentence); return implode(' ', array_map(function ($w) use ($langid) { return $this->translate_word($w, $langid); }, $words)); } function translate_multiline_text($text, $langid = 1) { $lines = explode("\n", $text); return implode("\n", array_map(function ($line) use ($langid) { return '- ' . $this->translate_sentence(ltrim($line, '- '), $langid); }, $lines)); } // ============================================================ // LOG ERROR // ============================================================ function insert_log_error($log_sql, $params, $data = '') { $sql = "INSERT INTO one_lab_log.error_log( ErrorLogCode, ErrorLogName, ErrorLogDescription, ErrorLogData, ErrorLogOrderCreated ) VALUES(?,?,?,?,NOW())"; $query = $this->db_smartone->query($sql, [ $params[0], $params[1], $log_sql, json_encode($data), ]); return (bool)$query; } }