diff --git a/admin/database_updates/2.5.4.php b/admin/database_updates/2.5.4.php new file mode 100644 index 00000000..a5e56415 --- /dev/null +++ b/admin/database_updates/2.5.4.php @@ -0,0 +1,16 @@ + +
+ +
+
+ +
+ +
+ The template's tasks are added to every ticket this schedule raises. +
+
- +
- +
@@ -343,6 +384,35 @@ ob_start();
+ + + diff --git a/agent/modals/recurring_ticket/recurring_ticket_edit.php b/agent/modals/recurring_ticket/recurring_ticket_edit.php index 69443692..22ad4a1e 100644 --- a/agent/modals/recurring_ticket/recurring_ticket_edit.php +++ b/agent/modals/recurring_ticket/recurring_ticket_edit.php @@ -20,6 +20,7 @@ $recurring_ticket_contact_id = intval($row['recurring_ticket_contact_id']); $recurring_ticket_asset_id = intval($row['recurring_ticket_asset_id']); $recurring_ticket_category = intval($row['recurring_ticket_category']); $recurring_ticket_billable = intval($row['recurring_ticket_billable']); +$recurring_ticket_ticket_template_id = intval($row['recurring_ticket_ticket_template_id']); // Additional Assets Selected $additional_assets_array = array(); @@ -69,18 +70,60 @@ ob_start();
+
+ +
+
+ +
+ +
+ The template's tasks are added to every ticket this schedule raises. Changing it rewrites the subject and details below. +
+
- +
- +
@@ -306,6 +349,35 @@ ob_start();
+ + + 0) { - while ($row = mysqli_fetch_assoc($sql_task_templates)) { - $task_order = intval($row['task_template_order']); - $task_name = escapeSql($row['task_template_name']); - $task_completion_estimate = intval($row['task_template_completion_estimate']); - - mysqli_query($mysqli,"INSERT INTO tasks SET task_name = '$task_name', task_order = $task_order, task_completion_estimate = $task_completion_estimate, task_ticket_id = $ticket_id"); - } - } - } + addTasksFromTicketTemplate($ticket_id, $ticket_template_id); // Add Watchers if (isset($_POST['watchers'])) { @@ -1705,10 +1692,6 @@ if (isset($_POST['bulk_add_asset_ticket'])) { $subject = escapeSql($row['ticket_template_subject']); } $details = mysqli_escape_string($mysqli, $row['ticket_template_details']); - - // Get Associated Tasks from the ticket template - $sql_task_templates = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id"); - } // Create ticket for each selected asset @@ -1770,16 +1753,7 @@ if (isset($_POST['bulk_add_asset_ticket'])) { } // Add Tasks from Template if Template was selected - if($ticket_template_id) { - if (mysqli_num_rows($sql_task_templates) > 0) { - while ($row = mysqli_fetch_assoc($sql_task_templates)) { - $task_order = intval($row['task_template_order']); - $task_name = escapeSql($row['task_template_name']); - - mysqli_query($mysqli,"INSERT INTO tasks SET task_name = '$task_name', task_order = $task_order, task_ticket_id = $ticket_id"); - } - } - } + addTasksFromTicketTemplate($ticket_id, $ticket_template_id); // Custom action/notif handler triggerCustomAction('ticket_create', $ticket_id); diff --git a/cron/cron.php b/cron/cron.php index 2dde102c..d7a1c62c 100644 --- a/cron/cron.php +++ b/cron/cron.php @@ -317,6 +317,7 @@ if (mysqli_num_rows($sql_recurring_tickets) > 0) { $contact_id = intval($row['recurring_ticket_contact_id']); $asset_id = intval($row['recurring_ticket_asset_id']); $category = intval($row['recurring_ticket_category']); + $ticket_template_id = intval($row['recurring_ticket_ticket_template_id']); $ticket_status = 1; // Default if ($assigned_id > 0) { @@ -351,6 +352,9 @@ if (mysqli_num_rows($sql_recurring_tickets) > 0) { FROM recurring_ticket_assets WHERE recurring_ticket_id = $recurring_ticket_id"); + // Copy Tasks from the linked ticket template, if one is set + addTasksFromTicketTemplate($id, $ticket_template_id); + // Logging logAudit("Ticket", "Create", "Cron created recurring scheduled $frequency ticket - $subject", $client_id, $id); diff --git a/db.sql b/db.sql index f47c68b6..89b7e2af 100644 --- a/db.sql +++ b/db.sql @@ -1937,6 +1937,7 @@ CREATE TABLE `recurring_tickets` ( `recurring_ticket_client_id` int(11) NOT NULL DEFAULT 0, `recurring_ticket_contact_id` int(11) NOT NULL DEFAULT 0, `recurring_ticket_asset_id` int(11) NOT NULL DEFAULT 0, + `recurring_ticket_ticket_template_id` int(11) NOT NULL DEFAULT 0, PRIMARY KEY (`recurring_ticket_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -3066,4 +3067,4 @@ CREATE TABLE `vendors` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2026-07-29 14:15:02 +-- Dump completed on 2026-07-29 15:54:34 diff --git a/functions/app.php b/functions/app.php index a3eb99a5..11a6a66a 100644 --- a/functions/app.php +++ b/functions/app.php @@ -71,6 +71,48 @@ function getTicketStatusName($ticket_status) { } +/** + * Copies a ticket template's tasks onto a ticket. + * + * Called anywhere a ticket is raised from a template - the ticket add modals, + * the bulk asset add, and every recurring ticket run (cron, force, bulk force). + * Tasks are a snapshot: editing the template later does not touch tickets that + * have already been raised from it. + * + * @param int $ticket_id The ticket to attach the tasks to. + * @param int $ticket_template_id The template to copy tasks from. 0 = no-op. + * + * @return int The number of tasks created. + */ +function addTasksFromTicketTemplate($ticket_id, $ticket_template_id) { + + global $mysqli; + + $ticket_id = intval($ticket_id); + $ticket_template_id = intval($ticket_template_id); + + if (!$ticket_id || !$ticket_template_id) { + return 0; + } + + $sql_task_templates = mysqli_query($mysqli, "SELECT * FROM task_templates WHERE task_template_ticket_template_id = $ticket_template_id ORDER BY task_template_order ASC"); + + $tasks_added = 0; + + while ($row = mysqli_fetch_assoc($sql_task_templates)) { + $task_order = intval($row['task_template_order']); + $task_name = escapeSql($row['task_template_name']); + $task_completion_estimate = intval($row['task_template_completion_estimate']); + + mysqli_query($mysqli, "INSERT INTO tasks SET task_name = '$task_name', task_order = $task_order, task_completion_estimate = $task_completion_estimate, task_ticket_id = $ticket_id"); + + $tasks_added++; + } + + return $tasks_added; + +} + /** * Retrieves a specified field's value from a table based on the record's id. * It validates the table and field names, automatically determines the primary key (or uses the first column as fallback),