conn = $conn; } /** * Get all recurring tickets */ public function getAll($includeInactive = false) { $sql = "SELECT rt.*, u1.display_name as assigned_name, u1.username as assigned_username, u2.display_name as creator_name, u2.username as creator_username FROM recurring_tickets rt LEFT JOIN users u1 ON rt.assigned_to = u1.user_id LEFT JOIN users u2 ON rt.created_by = u2.user_id"; if (!$includeInactive) { $sql .= " WHERE rt.is_active = 1"; } $sql .= " ORDER BY rt.next_run_at ASC"; $result = $this->conn->query($sql); $items = []; while ($row = $result->fetch_assoc()) { $items[] = $row; } return $items; } /** * Get a single recurring ticket by ID */ public function getById($recurringId) { $sql = "SELECT * FROM recurring_tickets WHERE recurring_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('i', $recurringId); $stmt->execute(); $result = $stmt->get_result(); $row = $result->fetch_assoc(); $stmt->close(); return $row; } /** * Create a new recurring ticket */ public function create($data) { $sql = "INSERT INTO recurring_tickets (title_template, description_template, category, type, priority, assigned_to, schedule_type, schedule_day, schedule_time, next_run_at, is_active, created_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('ssssiiisssis', $data['title_template'], $data['description_template'], $data['category'], $data['type'], $data['priority'], $data['assigned_to'], $data['schedule_type'], $data['schedule_day'], $data['schedule_time'], $data['next_run_at'], $data['is_active'], $data['created_by'] ); if ($stmt->execute()) { $id = $this->conn->insert_id; $stmt->close(); return ['success' => true, 'recurring_id' => $id]; } $error = $stmt->error; $stmt->close(); return ['success' => false, 'error' => $error]; } /** * Update a recurring ticket */ public function update($recurringId, $data) { $sql = "UPDATE recurring_tickets SET title_template = ?, description_template = ?, category = ?, type = ?, priority = ?, assigned_to = ?, schedule_type = ?, schedule_day = ?, schedule_time = ?, next_run_at = ?, is_active = ? WHERE recurring_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('ssssiissssii', $data['title_template'], $data['description_template'], $data['category'], $data['type'], $data['priority'], $data['assigned_to'], $data['schedule_type'], $data['schedule_day'], $data['schedule_time'], $data['next_run_at'], $data['is_active'], $recurringId ); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } /** * Delete a recurring ticket */ public function delete($recurringId) { $sql = "DELETE FROM recurring_tickets WHERE recurring_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('i', $recurringId); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } /** * Get recurring tickets due for execution */ public function getDueRecurringTickets() { $sql = "SELECT * FROM recurring_tickets WHERE is_active = 1 AND next_run_at <= NOW()"; $result = $this->conn->query($sql); $items = []; while ($row = $result->fetch_assoc()) { $items[] = $row; } return $items; } /** * Update last run and calculate next run time */ public function updateAfterRun($recurringId) { $recurring = $this->getById($recurringId); if (!$recurring) { return false; } $nextRun = $this->calculateNextRunTime( $recurring['schedule_type'], $recurring['schedule_day'], $recurring['schedule_time'] ); $sql = "UPDATE recurring_tickets SET last_run_at = NOW(), next_run_at = ? WHERE recurring_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('si', $nextRun, $recurringId); $success = $stmt->execute(); $stmt->close(); return $success; } /** * Calculate the next run time based on schedule */ private function calculateNextRunTime($scheduleType, $scheduleDay, $scheduleTime) { $now = new DateTime(); $time = new DateTime($scheduleTime); switch ($scheduleType) { case 'daily': $next = new DateTime('tomorrow ' . $scheduleTime); break; case 'weekly': $dayName = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][$scheduleDay] ?? 'Monday'; $next = new DateTime("next {$dayName} " . $scheduleTime); break; case 'monthly': $day = max(1, min(28, $scheduleDay)); // Limit to 28 for safety $next = new DateTime(); $next->modify('first day of next month'); $next->setDate($next->format('Y'), $next->format('m'), $day); $next->setTime($time->format('H'), $time->format('i'), 0); break; default: $next = new DateTime('tomorrow ' . $scheduleTime); } return $next->format('Y-m-d H:i:s'); } /** * Toggle active status */ public function toggleActive($recurringId) { $sql = "UPDATE recurring_tickets SET is_active = NOT is_active WHERE recurring_id = ?"; $stmt = $this->conn->prepare($sql); $stmt->bind_param('i', $recurringId); $success = $stmt->execute(); $stmt->close(); return ['success' => $success]; } } ?>