db_smartone = $CI->load->database("default", true); } function get_schedule_results_grouped($test_ids, $x_datetime, $branch_id, $order_id = null) { // Validasi input if (empty($test_ids) || empty($x_datetime) || empty($branch_id)) { return array("status" => "ERR", "message" => "Parameter tidak lengkap", "data" => array()); } // Konversi test_ids ke array integer if (is_array($test_ids)) { $test_ids_array = array_map('intval', $test_ids); } else { $test_ids_array = array_filter(array_map('intval', array_map('trim', explode(",", $test_ids)))); } if (empty($test_ids_array)) { return array("status" => "ERR", "message" => "Test IDs tidak valid", "data" => array()); } $branch_id_escaped = intval($branch_id); $test_ids_in = implode(",", $test_ids_array); // Pre-calculate untuk optimasi $x_datetime_ts = strtotime($x_datetime); $time_str = date('H:i', $x_datetime_ts); $date_str = date('Y-m-d', $x_datetime_ts); $day_of_week = date('w', $x_datetime_ts); // 0=Sunday, 6=Saturday $mysql_day_of_week = ($day_of_week == 0) ? 1 : $day_of_week + 1; // ============================================ // STEP 1: Ambil data test (query sederhana) // ============================================ $sql = "SELECT T_TestID, T_TestName, T_TestSasCode, T_TestParentT_TestID, T_TestNat_TestID, T_TestIsResult FROM t_test WHERE T_TestID IN ({$test_ids_in}) AND T_TestIsActive = 'Y'"; $query = $this->db_smartone->query($sql); if (!$query) { return array("status" => "ERR", "message" => "Gagal ambil data test", "data" => array()); } $tests = $query->result_array(); $test_list = array(); $parent_test_ids = array(); $sas_codes = array(); // Proses test: pisahkan yang result dan yang parent foreach ($tests as $test) { if ($test['T_TestIsResult'] == 'Y') { $test_list[$test['T_TestID']] = $test; } else { $parent_test_ids[] = $test['T_TestID']; $sas_codes[] = $this->db_smartone->escape($test['T_TestSasCode']); } } // Ambil child test dari parent (jika ada) if (!empty($sas_codes)) { $sql_parts = array(); foreach ($sas_codes as $sas_code) { $sql_parts[] = "T_TestSasCode LIKE CONCAT({$sas_code}, '%')"; } $sql = "SELECT T_TestID, T_TestName, T_TestSasCode, T_TestParentT_TestID, T_TestNat_TestID, T_TestIsResult FROM t_test WHERE (" . implode(" OR ", $sql_parts) . ") AND T_TestIsActive = 'Y' AND T_TestIsResult = 'Y'"; $query = $this->db_smartone->query($sql); if ($query) { $child_tests = $query->result_array(); foreach ($child_tests as $child) { $test_list[$child['T_TestID']] = $child; } } } if (empty($test_list)) { return array("status" => "OK", "message" => "No test found", "data" => array()); } // ============================================ // STEP 1.5: Ambil T_OrderDetailID jika order_id diberikan (setelah child test ditambahkan) // ============================================ $order_detail_map = array(); // [test_id => order_detail_id] if (!empty($order_id)) { $order_id_escaped = intval($order_id); // Ambil semua test_ids dari test_list (termasuk child yang baru ditambahkan) $all_test_ids = array_keys($test_list); $all_test_ids_in = implode(",", array_map('intval', $all_test_ids)); $sql = "SELECT T_OrderDetailID, T_OrderDetailT_TestID AS T_TestID FROM t_orderdetail WHERE T_OrderDetailT_OrderHeaderID = {$order_id_escaped} AND T_OrderDetailT_TestID IN ({$all_test_ids_in}) AND T_OrderDetailIsActive = 'Y'"; $query = $this->db_smartone->query($sql); if ($query) { $order_details = $query->result_array(); foreach ($order_details as $od) { $order_detail_map[$od['T_TestID']] = $od['T_OrderDetailID']; } } } // ============================================ // STEP 2: Ambil schedule untuk semua test (query sederhana) // ============================================ $nat_test_ids = array_unique(array_column($test_list, 'T_TestNat_TestID')); $nat_test_ids_in = implode(",", array_map('intval', $nat_test_ids)); $sql = "SELECT s.M_ScheduleID, s.M_ScheduleFlagAtTime, s.M_ScheduleAtTime, s.M_ScheduleMinute, s.M_ScheduleMonth, s.M_ScheduleWeek, s.M_ScheduleDay, s.M_ScheduleHour, s.M_ScheduleStartHourMinute, s.M_ScheduleEndHourMinute, sgt.M_ScheduleGroupTestNat_TestID AS Nat_TestID FROM m_schedule s INNER JOIN m_schedulegroup sg ON s.M_ScheduleM_ScheduleGroupID = sg.M_ScheduleGroupID INNER JOIN m_schedulegrouptest sgt ON sg.M_ScheduleGroupID = sgt.M_ScheduleGroupTestM_ScheduleGroupID WHERE s.M_ScheduleIsActive = 'Y' AND sg.M_ScheduleGroupIsActive = 'Y' AND sgt.M_ScheduleGroupTestIsActive = 'Y' AND sg.M_ScheduleGroupM_BranchID = {$branch_id_escaped} AND s.M_ScheduleDayOfWeek = {$mysql_day_of_week} AND sgt.M_ScheduleGroupTestNat_TestID IN ({$nat_test_ids_in}) AND '{$time_str}' >= s.M_ScheduleStartHourMinute AND '{$time_str}' <= s.M_ScheduleEndHourMinute"; $query = $this->db_smartone->query($sql); if (!$query) { return array("status" => "ERR", "message" => "Gagal ambil schedule", "data" => array()); } $schedules = $query->result_array(); //$this->order_debug('get_schedule_results_grouped/get_schedule', $this->db_smartone->last_query(), $schedules, "Ambil schedule untuk semua test"); // ============================================ // STEP 3: Proses di PHP - hitung janji hasil untuk setiap test // ============================================ $test_schedules = array(); // [test_id => [schedule1, schedule2, ...]] foreach ($test_list as $test_id => $test) { $test_schedules[$test_id] = array(); // Cari schedule untuk test ini foreach ($schedules as $schedule) { if ($schedule['Nat_TestID'] == $test['T_TestNat_TestID']) { // Hitung janji hasil if ($schedule['M_ScheduleFlagAtTime'] == 'Y') { $janji_hasil = $date_str . ' ' . $schedule['M_ScheduleAtTime'] . ':00'; } else { $janji_hasil_ts = $this->calculate_janji_hasil_ts($x_datetime_ts, $schedule); $janji_hasil = date('Y-m-d H:i:s', $janji_hasil_ts); $data_debug = array( 'test_id' => $test_id, 'test_name' => $test['T_TestName'], 'test_nat_test_id' => $test['T_TestNat_TestID'], 'schedule_id' => $schedule['M_ScheduleID'], 'schedule_flag_at_time' => $schedule['M_ScheduleFlagAtTime'], 'schedule_at_time' => $schedule['M_ScheduleAtTime'], 'schedule_month' => $schedule['M_ScheduleMonth'], 'schedule_week' => $schedule['M_ScheduleWeek'], 'schedule_day' => $schedule['M_ScheduleDay'], 'schedule_hour' => $schedule['M_ScheduleHour'], 'schedule_minute' => $schedule['M_ScheduleMinute'], 'schedule_start_hour_minute' => $schedule['M_ScheduleStartHourMinute'], 'schedule_end_hour_minute' => $schedule['M_ScheduleEndHourMinute'] ); //$this->order_debug('get_schedule_results_grouped/loop_schedule', '', $data_debug, "check schedule for test_id: $test_id"); } // Convert day, hour, minute to total minutes $tat_menit = ($schedule['M_ScheduleDay'] * 24 * 60) + ($schedule['M_ScheduleHour'] * 60) + $schedule['M_ScheduleMinute']; $test_schedules[$test_id][] = array( 'ScheduleID' => $schedule['M_ScheduleID'], 'JanjiHasil' => $janji_hasil, 'JanjiHasil_TS' => strtotime($janji_hasil), 'M_ScheduleFlagAtTime' => $schedule['M_ScheduleFlagAtTime'], 'M_ScheduleAtTime' => $schedule['M_ScheduleAtTime'], 'TAT_Menit' => $tat_menit, 'M_ScheduleStartHourMinute' => $schedule['M_ScheduleStartHourMinute'], 'M_ScheduleEndHourMinute' => $schedule['M_ScheduleEndHourMinute'] ); } } // Jika tidak ada schedule langsung, cari dari parent atau sibling if (empty($test_schedules[$test_id]) && !empty($test['T_TestParentT_TestID'])) { $parent_id = $test['T_TestParentT_TestID']; // Cari schedule dari parent foreach ($schedules as $schedule) { // Cek apakah ada test parent dengan nat_test_id yang sama foreach ($tests as $parent_test) { if ($parent_test['T_TestID'] == $parent_id && $parent_test['T_TestNat_TestID'] == $schedule['Nat_TestID']) { // Hitung janji hasil if ($schedule['M_ScheduleFlagAtTime'] == 'Y') { $janji_hasil = $date_str . ' ' . $schedule['M_ScheduleAtTime'] . ':00'; } else { $janji_hasil_ts = $this->calculate_janji_hasil_ts($x_datetime_ts, $schedule); $janji_hasil = date('Y-m-d H:i:s', $janji_hasil_ts); } // Convert day, hour, minute to total minutes $tat_menit = ($schedule['M_ScheduleDay'] * 24 * 60) + ($schedule['M_ScheduleHour'] * 60) + $schedule['M_ScheduleMinute']; $test_schedules[$test_id][] = array( 'ScheduleID' => $schedule['M_ScheduleID'], 'JanjiHasil' => $janji_hasil, 'JanjiHasil_TS' => strtotime($janji_hasil), 'M_ScheduleFlagAtTime' => $schedule['M_ScheduleFlagAtTime'], 'M_ScheduleAtTime' => $schedule['M_ScheduleAtTime'], 'TAT_Menit' => $tat_menit, 'M_ScheduleStartHourMinute' => $schedule['M_ScheduleStartHourMinute'], 'M_ScheduleEndHourMinute' => $schedule['M_ScheduleEndHourMinute'] ); break 2; // Break dari kedua loop } } } // Jika masih tidak ada, cari dari sibling (test lain dengan parent yang sama) if (empty($test_schedules[$test_id])) { foreach ($test_list as $sibling_id => $sibling_test) { if ($sibling_id != $test_id && $sibling_test['T_TestParentT_TestID'] == $parent_id) { // Cari schedule sibling foreach ($schedules as $schedule) { if ($sibling_test['T_TestNat_TestID'] == $schedule['Nat_TestID']) { if ($schedule['M_ScheduleFlagAtTime'] == 'Y') { $janji_hasil = $date_str . ' ' . $schedule['M_ScheduleAtTime'] . ':00'; } else { $janji_hasil_ts = $this->calculate_janji_hasil_ts($x_datetime_ts, $schedule); $janji_hasil = date('Y-m-d H:i:s', $janji_hasil_ts); } // Convert day, hour, minute to total minutes $tat_menit = ($schedule['M_ScheduleDay'] * 24 * 60) + ($schedule['M_ScheduleHour'] * 60) + $schedule['M_ScheduleMinute']; $test_schedules[$test_id][] = array( 'ScheduleID' => $schedule['M_ScheduleID'], 'JanjiHasil' => $janji_hasil, 'JanjiHasil_TS' => strtotime($janji_hasil), 'M_ScheduleFlagAtTime' => $schedule['M_ScheduleFlagAtTime'], 'M_ScheduleAtTime' => $schedule['M_ScheduleAtTime'], 'TAT_Menit' => $tat_menit, 'M_ScheduleStartHourMinute' => $schedule['M_ScheduleStartHourMinute'], 'M_ScheduleEndHourMinute' => $schedule['M_ScheduleEndHourMinute'] ); break 2; } } } } } // Jika masih tidak ada, default +24 jam if (empty($test_schedules[$test_id])) { $janji_hasil_ts = $x_datetime_ts + (24 * 3600); $test_schedules[$test_id][] = array( 'ScheduleID' => null, 'JanjiHasil' => date('Y-m-d H:i:s', $janji_hasil_ts), 'JanjiHasil_TS' => $janji_hasil_ts, 'M_ScheduleFlagAtTime' => null, 'M_ScheduleAtTime' => null, 'TAT_Menit' => null, 'M_ScheduleStartHourMinute' => null, 'M_ScheduleEndHourMinute' => null ); } } elseif (empty($test_schedules[$test_id])) { // Default +24 jam jika tidak ada schedule $janji_hasil_ts = $x_datetime_ts + (24 * 3600); $test_schedules[$test_id][] = array( 'ScheduleID' => null, 'JanjiHasil' => date('Y-m-d H:i:s', $janji_hasil_ts), 'JanjiHasil_TS' => $janji_hasil_ts, 'M_ScheduleFlagAtTime' => null, 'M_ScheduleAtTime' => null, 'TAT_Menit' => null, 'M_ScheduleStartHourMinute' => null, 'M_ScheduleEndHourMinute' => null ); } // Ambil schedule dengan janji hasil terbesar (ranking di PHP) usort($test_schedules[$test_id], function($a, $b) { return $b['JanjiHasil_TS'] - $a['JanjiHasil_TS']; }); } // ============================================ // STEP 4: Grouping berdasarkan tanggal dan jam (di PHP) // ============================================ $grouped = array(); // [group_key => [tests]] foreach ($test_schedules as $test_id => $schedules) { $best_schedule = $schedules[0]; // Sudah di-sort, ambil yang terbesar $test = $test_list[$test_id]; // Group key: tanggal + jam (tanpa detik) $janji_ts = $best_schedule['JanjiHasil_TS']; $group_key = date('Y-m-d H:i', $janji_ts); if (!isset($grouped[$group_key])) { $grouped[$group_key] = array( 'JanjiHasil' => $best_schedule['JanjiHasil'], 'JanjiHasil_Tanggal' => date('Y-m-d', $janji_ts), 'JanjiHasil_Waktu' => date('H:i:s', $janji_ts), 'TestIDs' => array(), 'TestNames' => array(), 'OrderDetailIDs' => array(), // Tambahkan untuk optimasi insert 'ScheduleID' => $best_schedule['ScheduleID'], 'M_ScheduleFlagAtTime' => $best_schedule['M_ScheduleFlagAtTime'], 'M_ScheduleAtTime' => $best_schedule['M_ScheduleAtTime'], 'TAT_Menit' => $best_schedule['TAT_Menit'], 'M_ScheduleStartHourMinute' => $best_schedule['M_ScheduleStartHourMinute'], 'M_ScheduleEndHourMinute' => $best_schedule['M_ScheduleEndHourMinute'] ); } $grouped[$group_key]['TestIDs'][] = $test_id; $grouped[$group_key]['TestNames'][] = $test['T_TestName']; // Tambahkan OrderDetailID jika ada if (!empty($order_detail_map[$test_id])) { $grouped[$group_key]['OrderDetailIDs'][] = $order_detail_map[$test_id]; } } // ============================================ // STEP 5: Format hasil akhir // ============================================ $results = array(); foreach ($grouped as $group) { $results[] = array( 'JanjiHasil_Tanggal' => $group['JanjiHasil_Tanggal'], 'JanjiHasil_Waktu' => $group['JanjiHasil_Waktu'], 'JanjiHasil' => $group['JanjiHasil'], 'TestIDs' => implode(',', $group['TestIDs']), 'TestNames' => implode(', ', $group['TestNames']), 'OrderDetailIDs' => !empty($group['OrderDetailIDs']) ? implode(',', $group['OrderDetailIDs']) : null, // Tambahkan OrderDetailIDs 'ScheduleID' => $group['ScheduleID'], 'M_ScheduleFlagAtTime' => $group['M_ScheduleFlagAtTime'], 'M_ScheduleAtTime' => $group['M_ScheduleAtTime'], 'TAT_Menit' => $group['TAT_Menit'], 'M_ScheduleStartHourMinute' => $group['M_ScheduleStartHourMinute'], 'M_ScheduleEndHourMinute' => $group['M_ScheduleEndHourMinute'] ); } // Sort by tanggal dan waktu usort($results, function($a, $b) { $ts_a = strtotime($a['JanjiHasil']); $ts_b = strtotime($b['JanjiHasil']); return $ts_a - $ts_b; }); return $results; } /** * Helper function untuk menghitung janji_hasil_ts berdasarkan schedule * Memperhitungkan M_ScheduleMonth, M_ScheduleWeek, M_ScheduleDay, M_ScheduleHour, dan M_ScheduleMinute * * @param int $base_ts - Base timestamp * @param array $schedule - Array schedule data * @return int - Timestamp hasil perhitungan */ private function calculate_janji_hasil_ts($base_ts, $schedule) { $dt = new DateTime(); $dt->setTimestamp($base_ts); // Tambahkan M_ScheduleMonth (jika ada) if (!empty($schedule['M_ScheduleMonth']) && $schedule['M_ScheduleMonth'] > 0) { $dt->modify('+' . intval($schedule['M_ScheduleMonth']) . ' months'); } // Tambahkan M_ScheduleWeek (jika ada) if (!empty($schedule['M_ScheduleWeek']) && $schedule['M_ScheduleWeek'] > 0) { $dt->modify('+' . intval($schedule['M_ScheduleWeek']) . ' weeks'); } // Tambahkan M_ScheduleDay (jika ada) if (!empty($schedule['M_ScheduleDay']) && $schedule['M_ScheduleDay'] > 0) { $dt->modify('+' . intval($schedule['M_ScheduleDay']) . ' days'); } // Tambahkan M_ScheduleHour (jika ada) if (!empty($schedule['M_ScheduleHour']) && $schedule['M_ScheduleHour'] > 0) { $dt->modify('+' . intval($schedule['M_ScheduleHour']) . ' hours'); } // Tambahkan M_ScheduleMinute (jika ada) if (!empty($schedule['M_ScheduleMinute']) && $schedule['M_ScheduleMinute'] > 0) { $dt->modify('+' . intval($schedule['M_ScheduleMinute']) . ' minutes'); } return $dt->getTimestamp(); } }