From 6e1ae01cac47b285505e976166afc4a9c70f99cb Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sun, 5 Apr 2026 18:16:41 -0400 Subject: [PATCH] Fix recurring ticket schedule edge cases in API and model MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - manage_recurring.php calculateNextRun(): expand monthly cap from 28→31 with proper last-day-of-month clamping (matches model fix); use split with ':00' append to handle malformed time strings without crashing; fix weekly day array to start at index 1 (not 0) so day=0 never maps to empty string and blows up DateTime - RecurringTicketModel::calculateNextRunTime(): same weekly day array fix (start at index 1) to eliminate '' → DateTime exception on day=0 Co-Authored-By: Claude Sonnet 4.6 --- api/manage_recurring.php | 15 +++++++++------ models/RecurringTicketModel.php | 3 ++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/api/manage_recurring.php b/api/manage_recurring.php index 546c629..cfff818 100644 --- a/api/manage_recurring.php +++ b/api/manage_recurring.php @@ -147,18 +147,21 @@ function calculateNextRun($scheduleType, $scheduleDay, $scheduleTime) { break; case 'weekly': - $days = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; - $dayName = $days[$scheduleDay] ?? 'Monday'; + $days = [1 => 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + $dayName = $days[(int)$scheduleDay] ?? 'Monday'; $next = new DateTime("next {$dayName} " . $time); break; case 'monthly': - $day = max(1, min(28, (int)$scheduleDay)); + $day = max(1, min(31, (int)$scheduleDay)); $next = new DateTime(); $next->modify('first day of next month'); - $next->setDate($next->format('Y'), $next->format('m'), $day); - list($h, $m) = explode(':', $time); - $next->setTime((int)$h, (int)$m, 0); + // Clamp to last day of target month (handles Feb, 30-day months) + $daysInMonth = (int)$next->format('t'); + $day = min($day, $daysInMonth); + $next->setDate((int)$next->format('Y'), (int)$next->format('m'), $day); + $parts = explode(':', $time . ':00'); // ensure at least H:M + $next->setTime((int)$parts[0], (int)$parts[1], 0); break; default: diff --git a/models/RecurringTicketModel.php b/models/RecurringTicketModel.php index 8d0f3f8..a066bca 100644 --- a/models/RecurringTicketModel.php +++ b/models/RecurringTicketModel.php @@ -176,7 +176,8 @@ class RecurringTicketModel { break; case 'weekly': - $dayName = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][$scheduleDay] ?? 'Monday'; + $dayNames = [1 => 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; + $dayName = $dayNames[(int)$scheduleDay] ?? 'Monday'; $next = new DateTime("next {$dayName} " . $scheduleTime); break;