Files
dnssash/adm/consultant_manage/schedule_generator.php
2026-06-11 18:47:38 +09:00

376 lines
12 KiB
PHP

<?php
/**
* 월별 스케줄 자동 생성 엔진
*/
if (!defined('_GNUBOARD_'))
exit;
class ScheduleGenerator
{
/**
* 특정 월의 전체 스케줄 생성
*/
public function generateMonth($year, $month)
{
try {
// 기본 설정 조회
$basic_settings = $this->getBasicSettings();
// 요일별 설정 조회
$weekly_settings = $this->getWeeklySettings();
// 해당 월의 모든 날짜 생성
$dates = $this->getMonthDates($year, $month);
// 기존 스케줄 삭제 (자동 생성된 것만)
$this->clearAutoGeneratedSchedule($year, $month);
$generated_count = 0;
foreach ($dates as $date) {
$day_of_week = date('w', strtotime($date)); // 0=일요일, 1=월요일, ...
$day_name = $this->getDayName($day_of_week);
// 해당 요일의 설정 확인
if (isset($weekly_settings[$day_name]) && $weekly_settings[$day_name]['enabled'] == '1') {
// 운영일인 경우 스케줄 생성
$slots_created = $this->generateDay($date, $weekly_settings[$day_name], $basic_settings);
$generated_count += $slots_created;
} else {
// 휴무일인 경우 휴무 표시
$this->createHolidaySlot($date, '휴무일');
}
}
consultant_log("월별 스케줄 생성 완료: {$year}-{$month}, 생성된 슬롯: {$generated_count}");
return $generated_count;
} catch (Exception $e) {
consultant_log("월별 스케줄 생성 실패: " . $e->getMessage(), 'error');
throw $e;
}
}
/**
* 특정 날짜의 스케줄 생성
*/
public function generateDay($date, $day_settings, $basic_settings)
{
$slots_created = 0;
try {
$start_time = $day_settings['start'];
$end_time = $day_settings['end'];
$lunch_start = $day_settings['lunch_start'];
$lunch_end = $day_settings['lunch_end'];
$slot_duration = (int) $basic_settings['consultation_duration'];
$max_persons = (int) $basic_settings['max_persons_per_slot'];
// 시간 슬롯 생성
$current_time = strtotime($start_time);
$end_timestamp = strtotime($end_time);
while ($current_time < $end_timestamp) {
$slot_start = date('H:i', $current_time);
$slot_end = date('H:i', $current_time + ($slot_duration * 60));
// 종료시간이 운영시간을 넘지 않도록 체크
if (strtotime($slot_end) > $end_timestamp) {
break;
}
// 점심시간 체크
$is_lunch_time = $this->isLunchTime($slot_start, $slot_end, $lunch_start, $lunch_end);
if ($is_lunch_time) {
// 점심시간 슬롯 생성
$this->createTimeSlot($date, $slot_start, $slot_end, $slot_duration, 0, 0, 'lunch_time');
} else {
// 일반 상담 슬롯 생성
$this->createTimeSlot($date, $slot_start, $slot_end, $slot_duration, $max_persons, 1, 'auto_generated');
}
$slots_created++;
$current_time += ($slot_duration * 60);
}
return $slots_created;
} catch (Exception $e) {
consultant_log("일별 스케줄 생성 실패 ({$date}): " . $e->getMessage(), 'error');
throw $e;
}
}
/**
* 시간 슬롯 생성
*/
private function createTimeSlot($date, $start_time, $end_time, $duration, $max_persons, $is_available, $type)
{
$sql = "INSERT INTO consultant_schedule
(specific_date, start_time, end_time, time_slot, max_persons, is_available, temp_1, created_at)
VALUES
('{$date}', '{$start_time}', '{$end_time}', {$duration}, {$max_persons}, {$is_available}, '{$type}', NOW())";
return sql_query($sql);
}
/**
* 휴무일 슬롯 생성
*/
private function createHolidaySlot($date, $reason = '휴무일')
{
$sql = "INSERT INTO consultant_schedule
(specific_date, start_time, end_time, time_slot, max_persons, is_available, temp_1, temp_2, created_at)
VALUES
('{$date}', '00:00', '23:59', 0, 0, 0, 'holiday', '{$reason}', NOW())";
return sql_query($sql);
}
/**
* 점심시간 여부 확인
*/
private function isLunchTime($slot_start, $slot_end, $lunch_start, $lunch_end)
{
if (empty($lunch_start) || empty($lunch_end)) {
return false;
}
$slot_start_time = strtotime($slot_start);
$slot_end_time = strtotime($slot_end);
$lunch_start_time = strtotime($lunch_start);
$lunch_end_time = strtotime($lunch_end);
// 슬롯이 점심시간과 겹치는지 확인
return ($slot_start_time >= $lunch_start_time && $slot_start_time < $lunch_end_time) ||
($slot_end_time > $lunch_start_time && $slot_end_time <= $lunch_end_time) ||
($slot_start_time <= $lunch_start_time && $slot_end_time >= $lunch_end_time);
}
/**
* 해당 월의 모든 날짜 배열 생성
*/
private function getMonthDates($year, $month)
{
$dates = [];
$days_in_month = cal_days_in_month(CAL_GREGORIAN, $month, $year);
for ($day = 1; $day <= $days_in_month; $day++) {
$dates[] = sprintf('%04d-%02d-%02d', $year, $month, $day);
}
return $dates;
}
/**
* 요일 숫자를 요일명으로 변환
*/
private function getDayName($day_of_week)
{
$day_names = [
0 => 'sunday',
1 => 'monday',
2 => 'tuesday',
3 => 'wednesday',
4 => 'thursday',
5 => 'friday',
6 => 'saturday'
];
return $day_names[$day_of_week] ?? 'sunday';
}
/**
* 기본 설정 조회
*/
private function getBasicSettings()
{
return [
'consultation_duration' => consultant_get_config('consultation_duration', '60'),
'max_persons_per_slot' => consultant_get_config('max_persons_per_slot', '2'),
'consultation_fee' => consultant_get_config('consultation_fee', '50000')
];
}
/**
* 요일별 설정 조회
*/
private function getWeeklySettings()
{
$days = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'];
$settings = [];
foreach ($days as $day) {
$settings[$day] = [
'enabled' => consultant_get_config($day . '_enabled', $day == 'saturday' || $day == 'sunday' ? '0' : '1'),
'start' => consultant_get_config($day . '_start', '09:00'),
'end' => consultant_get_config($day . '_end', '18:00'),
'lunch_start' => consultant_get_config($day . '_lunch_start', '12:00'),
'lunch_end' => consultant_get_config($day . '_lunch_end', '13:00')
];
}
return $settings;
}
/**
* 자동 생성된 스케줄 삭제
*/
private function clearAutoGeneratedSchedule($year, $month)
{
$start_date = sprintf('%04d-%02d-01', $year, $month);
$end_date = sprintf('%04d-%02d-%02d', $year, $month, cal_days_in_month(CAL_GREGORIAN, $month, $year));
// 기존 예약이 없는 자동 생성 스케줄만 삭제
$sql = "DELETE cs FROM consultant_schedule cs
LEFT JOIN consultant_reservations cr ON (
cs.specific_date = cr.reservation_date
AND cs.start_time = cr.reservation_time
AND cr.is_deleted = 0
)
WHERE cs.specific_date >= '{$start_date}'
AND cs.specific_date <= '{$end_date}'
AND cs.temp_1 IN ('auto_generated', 'lunch_time', 'holiday')
AND cr.id IS NULL";
return sql_query($sql);
}
/**
* 기존 예약 보호 - 예약이 있는 시간대 확인
*/
public function getExistingReservations($year, $month)
{
$start_date = sprintf('%04d-%02d-01', $year, $month);
$end_date = sprintf('%04d-%02d-%02d', $year, $month, cal_days_in_month(CAL_GREGORIAN, $month, $year));
$sql = "SELECT reservation_date, reservation_time, COUNT(*) as count
FROM consultant_reservations
WHERE reservation_date >= '{$start_date}'
AND reservation_date <= '{$end_date}'
AND is_deleted = 0
GROUP BY reservation_date, reservation_time";
$result = sql_query($sql);
$reservations = [];
if ($result) {
while ($row = sql_fetch_array($result)) {
$key = $row['reservation_date'] . '_' . $row['reservation_time'];
$reservations[$key] = $row['count'];
}
}
return $reservations;
}
/**
* 다음 달 스케줄 자동 생성 (크론잡용)
*/
public function generateNextMonth()
{
$next_month = date('Y-m', strtotime('+1 month'));
list($year, $month) = explode('-', $next_month);
return $this->generateMonth((int) $year, (int) $month);
}
/**
* 스케줄 생성 상태 확인
*/
public function checkScheduleStatus($year, $month)
{
$start_date = sprintf('%04d-%02d-01', $year, $month);
$end_date = sprintf('%04d-%02d-%02d', $year, $month, cal_days_in_month(CAL_GREGORIAN, $month, $year));
$sql = "SELECT
COUNT(*) as total_slots,
COUNT(CASE WHEN temp_1 = 'auto_generated' THEN 1 END) as auto_slots,
COUNT(CASE WHEN temp_1 = 'lunch_time' THEN 1 END) as lunch_slots,
COUNT(CASE WHEN temp_1 = 'holiday' THEN 1 END) as holiday_slots,
COUNT(CASE WHEN temp_1 = 'admin_blocked' THEN 1 END) as blocked_slots
FROM consultant_schedule
WHERE specific_date >= '{$start_date}'
AND specific_date <= '{$end_date}'";
return sql_fetch($sql);
}
/**
* 설정 변경 시 영향받는 예약 확인
*/
public function checkSettingConflicts($year, $month)
{
$existing_reservations = $this->getExistingReservations($year, $month);
$conflicts = [];
// 새로운 설정으로 생성될 스케줄과 기존 예약 비교
$weekly_settings = $this->getWeeklySettings();
$dates = $this->getMonthDates($year, $month);
foreach ($dates as $date) {
$day_of_week = date('w', strtotime($date));
$day_name = $this->getDayName($day_of_week);
// 휴무일로 변경되었는데 예약이 있는 경우
if (!isset($weekly_settings[$day_name]) || $weekly_settings[$day_name]['enabled'] != '1') {
foreach ($existing_reservations as $key => $count) {
if (strpos($key, $date) === 0) {
$conflicts[] = [
'date' => $date,
'type' => 'holiday_conflict',
'message' => "{$date}는 휴무일로 설정되었지만 {$count}건의 예약이 있습니다."
];
}
}
}
}
return $conflicts;
}
}
/**
* 스케줄 생성 헬퍼 함수들
*/
/**
* 월별 스케줄 생성 실행
*/
function generate_monthly_schedule($year, $month)
{
$generator = new ScheduleGenerator();
return $generator->generateMonth($year, $month);
}
/**
* 다음 달 스케줄 자동 생성
*/
function auto_generate_next_month_schedule()
{
$generator = new ScheduleGenerator();
return $generator->generateNextMonth();
}
/**
* 스케줄 생성 상태 확인
*/
function get_schedule_generation_status($year, $month)
{
$generator = new ScheduleGenerator();
return $generator->checkScheduleStatus($year, $month);
}
/**
* 설정 변경 영향 확인
*/
function check_schedule_setting_conflicts($year, $month)
{
$generator = new ScheduleGenerator();
return $generator->checkSettingConflicts($year, $month);
}
?>