/home/techb158/workloadmatch.com/Manager
Edit: /home/techb158/workloadmatch.com/Manager/rewrite_ajax_replace_saturday.php (13189B)
prepare("SELECT Time_Slot, Time_From, Time_To, class_days, Weekend_Class FROM manager_group_name WHERE Group_ID = ?");
$stmt->bind_param('i', $groupID);
$stmt->execute();
$row = $stmt->get_result()->fetch_assoc();
$stmt->close();
return $row;
}
// This function exists in the original ajax file; kept for compatibility (not used in the active path).
function fetch_slot_times($mysqli, $slotLabels, $managerStart, $managerEnd) {
$timeFrom = [];
$timeTo = [];
foreach ($slotLabels as $label) {
$stmt = $mysqli->prepare('SELECT Time_From, Time_To FROM time_slot_programs WHERE Time_Slot = ?');
$stmt->bind_param('s', $label);
$stmt->execute();
$res = $stmt->get_result();
if ($row = $res->fetch_assoc()) {
$timeFrom[] = $row['Time_From'];
$timeTo[] = $row['Time_To'];
} else {
$timeFrom[] = $managerStart->format('H:i:s');
$timeTo[] = $managerEnd->format('H:i:s');
}
$stmt->close();
}
return [$timeFrom, $timeTo];
}
// Holidays using overlap window (same approach as Create_Schedule_Algorithm.php)
function get_holidays($mysqli, $Start_Date, $End_Date = null) {
$holidays = [];
if ($End_Date === null) {
$End_Date = date('Y-m-d', strtotime('+1 year', strtotime($Start_Date)));
}
$stmt = $mysqli->prepare(
"SELECT Event_Title, Event_Start, Event_End\n FROM Events\n WHERE Event_Start <= ?\n AND Event_End >= ?"
);
$stmt->bind_param('ss', $End_Date, $Start_Date);
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$start = new DateTime($row['Event_Start']);
$end = new DateTime($row['Event_End']);
while ($start <= $end) {
$holidays[] = $start->format('Y-m-d');
$start->modify('+1 day');
}
}
$stmt->close();
return array_values(array_unique($holidays));
}
function get_retake_dates($mysqli, $programID, $groupID) {
$retakes = [];
$stmt = $mysqli->prepare('SELECT Retake_Date FROM retake_records WHERE Program_ID = ? AND Group_ID = ?');
$stmt->bind_param('ii', $programID, $groupID);
$stmt->execute();
$res = $stmt->get_result();
while ($row = $res->fetch_assoc()) {
$retakes[] = $row['Retake_Date'];
}
$stmt->close();
return $retakes;
}
function generate_valid_dates($Start_Date, $End_Date, $classDays, $holidayDates, $retakeDates) {
$validDates = [];
$cur = new DateTime($Start_Date);
$end = $End_Date ? new DateTime($End_Date) : null;
while (!$end || $cur <= $end) {
$day = $cur->format('l');
$dateStr = $cur->format('Y-m-d');
$month = (int)$cur->format('m');
if (in_array($dateStr, $holidayDates, true)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Holiday'];
} elseif (in_array($dateStr, $retakeDates, true)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Retake'];
} elseif ($month !== 7 && in_array($day, $classDays, true)) {
$validDates[] = ['Date' => $dateStr, 'Type' => 'Class'];
}
$cur->modify('+1 day');
if ($end === null && count($validDates) > 500) break;
}
return $validDates;
}
function calculate_session_length($timeFrom, $timeTo) {
$sessionLength = 0;
foreach ($timeFrom as $i => $from) {
$fromTime = new DateTime($from);
$toTime = new DateTime($timeTo[$i]);
$sessionLength += ($toTime->getTimestamp() - $fromTime->getTimestamp()) / 3600;
}
$slotCount = count($timeFrom);
return $slotCount > 0 ? $sessionLength / $slotCount : 3;
}
function calculate_course_sessions($mysqli, $Program_ID, $sessionLength) {
$courseSessions = [];
$res = $mysqli->query("SELECT Course_ID, Course_Time FROM Courses WHERE Program_ID = $Program_ID");
while ($row = $res->fetch_assoc()) {
$courseID = $row['Course_ID'];
$courseHours = $row['Course_Time'];
$courseSessions[$courseID] = ceil($courseHours / $sessionLength);
}
return $courseSessions;
}
function getNextCourseForSlot($remainingSessions, $courseList, $usedToday) {
$available = array_filter($courseList, function($courseID) use ($remainingSessions) {
return ($remainingSessions[$courseID] ?? 0) > 0;
});
$unusedToday = array_filter($available, function($courseID) use ($usedToday) {
return !in_array($courseID, $usedToday, true);
});
if (!empty($unusedToday)) {
return reset($unusedToday);
}
if (count($available) === 1) {
return reset($available);
}
return null;
}
// ------------------- AJAX handler (active logic only) -------------------
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['status' => 'error', 'message' => 'Invalid request method.']);
exit;
}
$Program_ID = (int)($_POST['Program_ID'] ?? 0);
$Group_ID = (int)($_POST['Group_ID'] ?? 0);
$Start_Date = (string)($_POST['Start_Date'] ?? '');
$Removed_Date = (string)($_POST['date'] ?? '');
$selectedCourses = json_decode($_POST['Selected_Courses'] ?? '[]', true) ?? [];
$priorityCourses = json_decode($_POST['Priority_Course'] ?? '{}', true) ?? [];
$Course_Sessions = json_decode($_POST['Course_Sessions'] ?? '{}', true) ?? [];
if ($Program_ID <= 0 || $Group_ID <= 0 || $Start_Date === '' || $Removed_Date === '') {
echo json_encode(['status' => 'error', 'message' => 'Missing required fields']);
exit;
}
// Reset deleted Saturdays when changing group
$lastGroup = $_SESSION['last_group_id'] ?? null;
if ($Group_ID !== $lastGroup) {
unset($_SESSION['deletedSaturdays']);
}
$_SESSION['last_group_id'] = $Group_ID;
$group = get_group_info($mysqli, $Group_ID);
if (!$group) {
echo json_encode(['status' => 'error', 'message' => 'Group not found']);
exit;
}
$classDays = array_map('trim', explode(',', (string)$group['class_days']));
// Slots from group_slot_mapping (as in your active logic)
$stmt = $mysqli->prepare('SELECT Group_Slot_ID, Time_Slot, Time_From, Time_To FROM group_slot_mapping WHERE Group_ID = ?');
$stmt->bind_param('i', $Group_ID);
$stmt->execute();
$res = $stmt->get_result();
$slotLabels = [];
$timeFrom = [];
$timeTo = [];
$slotData = [];
while ($row = $res->fetch_assoc()) {
$slotLabels[] = $row['Time_Slot'];
$timeFrom[] = $row['Time_From'];
$timeTo[] = $row['Time_To'];
$slotData[] = [
'Group_Slot_ID' => $row['Group_Slot_ID'],
'Time_Slot' => $row['Time_Slot'],
'Time_From' => $row['Time_From'],
'Time_To' => $row['Time_To'],
];
}
$stmt->close();
if (count($slotData) === 0) {
echo json_encode(['status' => 'error', 'message' => "No slot data found for Group_ID = $Group_ID"]);
exit;
}
$sessionLength = calculate_session_length($timeFrom, $timeTo);
$holidayDates = get_holidays($mysqli, $Start_Date);
$retakeDates = get_retake_dates($mysqli, $Program_ID, $Group_ID);
$validDates = generate_valid_dates($Start_Date, null, $classDays, $holidayDates, $retakeDates);
// Store deleted Saturdays in session and remove them from validDates
$deletedSaturdays = $_SESSION['deletedSaturdays'] ?? [];
$deletedSaturdays[] = $Removed_Date;
$_SESSION['deletedSaturdays'] = array_values(array_unique($deletedSaturdays));
$validDates = array_filter($validDates, function($d) use ($deletedSaturdays) {
return !in_array($d['Date'], $deletedSaturdays, true);
});
$validDates = array_values($validDates);
// Reorder courses by priority
if (!empty($priorityCourses)) {
usort($selectedCourses, function($a, $b) use ($priorityCourses) {
return ($priorityCourses[$a] ?? PHP_INT_MAX) <=> ($priorityCourses[$b] ?? PHP_INT_MAX);
});
}
// Course names
$courseNames = [];
$res = $mysqli->query("SELECT Course_ID, Course_Name FROM Courses WHERE Program_ID = $Program_ID");
while ($row = $res->fetch_assoc()) {
$courseNames[$row['Course_ID']] = $row['Course_Name'];
}
// Use custom sessions from Course_Sessions payload
$courseSessions = [];
foreach ($selectedCourses as $courseID) {
$custom = $Course_Sessions[$courseID] ?? null;
$courseSessions[$courseID] = (is_numeric($custom) && $custom > 0) ? (int)$custom : 0;
}
$remainingSessions = [];
foreach ($selectedCourses as $courseID) {
$remainingSessions[$courseID] = $courseSessions[$courseID] ?? 0;
}
// Build schedule HTML and ajaxScheduleData
$html = "";
$html .= "
";
$html .= "| Date | Slot | Time | Course | Action |
";
$currentCourse = reset($selectedCourses);
$slotCount = count($slotLabels);
$slotIndex = 0;
$ajaxScheduleData = [];
foreach ($validDates as $entry) {
$date = $entry['Date'];
$dayName = (new DateTime($date))->format('l');
$type = $entry['Type'];
if ($type === 'Holiday') {
$html .= "";
$html .= "| ($dayName) $date | - | - | HOLIDAY | - | ";
$html .= "
";
continue;
}
if ($type === 'Retake') {
$html .= "";
$html .= "| ($dayName) $date | - | - | RETAKE | - | ";
$html .= "
";
continue;
}
if (!$currentCourse) break;
$slotLabel = format_time_slot_label($slotLabels[$slotIndex % $slotCount], $dayName);
$timeRange = format_time_slot_range(
$slotLabels[$slotIndex % $slotCount],
$timeFrom[$slotIndex % $slotCount],
$timeTo[$slotIndex % $slotCount],
$dayName
);
$examTag = ((int)($remainingSessions[$currentCourse] ?? 0) === 1) ? ' (Exam Day)' : '';
$normalizedDate = (new DateTime($date))->format('Y-m-d');
$deletedSaturdays = $_SESSION['deletedSaturdays'] ?? [];
if ($dayName === 'Saturday') {
if (in_array($normalizedDate, $deletedSaturdays, true)) {
$action = 'ðŸ—‘ï¸ Removed';
} else {
$action = "";
}
} else {
$action = '-';
}
$currentSlot = $slotData[$slotIndex % count($slotData)];
$groupSlotID = $currentSlot['Group_Slot_ID'];
$slotLabelReal = $currentSlot['Time_Slot'];
$from = $currentSlot['Time_From'];
$to = $currentSlot['Time_To'];
$html .= "";
$ajaxScheduleData[] = [
'program_id' => $Program_ID,
'course_id' => $currentCourse,
'course_name' => $courseNames[$currentCourse] ?? '',
'group_id' => $Group_ID,
'group_slot_id' => $groupSlotID,
'reserve_course' => 0,
'time_slot' => $slotLabelReal,
'start_date' => $date,
'end_date' => $date,
'start_time' => $from,
'end_time' => $to,
];
$courseName = $courseNames[$currentCourse] ?? '';
$html .= "| ($dayName) $date | $slotLabelReal | $timeRange | {$courseName}{$examTag} | $action | ";
$html .= "
";
$remainingSessions[$currentCourse]--;
if (($remainingSessions[$currentCourse] ?? 0) <= 0) {
$currentCourse = next($selectedCourses);
}
$slotIndex++;
}
$html .= "";
$html .= "| Date | Slot | Time | Course | Action |
";
$html .= "
";
echo json_encode([
'status' => 'success',
'html' => $html,
'ajaxScheduleData' => $ajaxScheduleData,
]);
exit;