false, 'ERROR' => 'missing_params', 'MESSAGE' => 'BusinessID is required']); } if ($taskID <= 0) { apiAbort(['OK' => false, 'ERROR' => 'missing_params', 'MESSAGE' => 'ScheduledTaskID is required']); } try { $existing = queryOne(" SELECT ID, CronExpression, COALESCE(ScheduleType, 'cron') AS ScheduleType, IntervalMinutes FROM ScheduledTaskDefinitions WHERE ID = ? AND BusinessID = ? ", [$taskID, $businessID]); if (!$existing) { apiAbort(['OK' => false, 'ERROR' => 'not_found', 'MESSAGE' => 'Scheduled task not found']); } if ($isActive) { // Recalculate next run time based on schedule type $st = $existing['ScheduleType']; $interval = (int) ($existing['IntervalMinutes'] ?? 0); if (($st === 'interval' || $st === 'interval_after_completion') && $interval > 0) { $nextRun = new DateTime("+{$interval} minutes", new DateTimeZone('UTC')); } else { $nextRun = calculateNextRun($existing['CronExpression']); } queryTimed("UPDATE ScheduledTaskDefinitions SET IsActive = 1, NextRunOn = ? WHERE ID = ?", [ $nextRun->format('Y-m-d H:i:s'), $taskID, ]); } else { queryTimed("UPDATE ScheduledTaskDefinitions SET IsActive = 0 WHERE ID = ?", [$taskID]); } jsonResponse([ 'OK' => true, 'MESSAGE' => $isActive ? 'Scheduled task enabled' : 'Scheduled task disabled', ]); } catch (Exception $e) { jsonResponse(['OK' => false, 'ERROR' => 'server_error', 'MESSAGE' => $e->getMessage()]); }