Feature: Abiliry to assign Ticket Templates to Recurring Tickets

This commit is contained in:
johnnyq
2026-07-29 15:55:14 -04:00
parent 9c123c42d1
commit bc64c9e3d1
9 changed files with 223 additions and 35 deletions

View File

@@ -84,18 +84,59 @@ ob_start();
<?php } ?>
<div class="form-group">
<label>Template</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<select class="form-control select2" id="ticket_template_select" name="ticket_template_id">
<option value="0">- No Template -</option>
<?php
$sql_ticket_templates = mysqli_query($mysqli, "
SELECT tt.ticket_template_id,
tt.ticket_template_name,
tt.ticket_template_subject,
tt.ticket_template_details,
COUNT(ttt.task_template_id) as task_count
FROM ticket_templates tt
LEFT JOIN task_templates ttt
ON tt.ticket_template_id = ttt.task_template_ticket_template_id
WHERE tt.ticket_template_archived_at IS NULL
GROUP BY tt.ticket_template_id
ORDER BY tt.ticket_template_name ASC
");
while ($row = mysqli_fetch_assoc($sql_ticket_templates)) {
$ticket_template_id_select = intval($row['ticket_template_id']);
$ticket_template_name_select = escapeHtml($row['ticket_template_name']);
$ticket_template_subject_select = escapeHtml($row['ticket_template_subject']);
$ticket_template_details_select = escapeHtml($row['ticket_template_details']);
$task_count = intval($row['task_count']);
?>
<option value="<?= $ticket_template_id_select ?>"
data-subject="<?= $ticket_template_subject_select ?>"
data-details="<?= $ticket_template_details_select ?>">
<?= $ticket_template_name_select ?> (<?= $task_count ?> tasks)
</option>
<?php } ?>
</select>
</div>
<small class="form-text text-muted">The template's tasks are added to every ticket this schedule raises.</small>
</div>
<div class="form-group">
<label>Subject <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500" required>
<input type="text" class="form-control" id="subjectInput" name="subject" placeholder="Subject" maxlength="500" required>
</div>
</div>
<div class="form-group">
<textarea class="form-control tinymceTicket" name="details"></textarea>
<textarea class="form-control tinymceTicket" id="detailsInput" name="details"></textarea>
</div>
<div class="row">
@@ -343,6 +384,35 @@ ob_start();
</div>
</form>
<!-- Ticket Templates -->
<script>
$(document).on('change', '#ticket_template_select', function () {
const $opt = $(this).find(':selected');
// Selecting "- No Template -" only unlinks the template - it must not wipe
// whatever subject/details the user has already written
if (!parseInt($opt.val(), 10)) {
return;
}
const templateSubject = $opt.data('subject') || '';
const templateDetails = $opt.data('details') || '';
$('#subjectInput').val(templateSubject);
if (window.tinymce) {
const editor = tinymce.get('detailsInput');
if (editor) {
editor.setContent(templateDetails);
} else {
$('#detailsInput').val(templateDetails);
}
} else {
$('#detailsInput').val(templateDetails);
}
});
</script>
<!-- Recurring Ticket Client/Contact JS -->
<link rel="stylesheet" href="/libs/jquery-ui/jquery-ui.min.css">
<script src="/libs/jquery-ui/jquery-ui.min.js"></script>

View File

@@ -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();
<div class="tab-pane fade show active" id="pills-edit-details">
<div class="form-group">
<label>Template</label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-cube"></i></span>
</div>
<select class="form-control select2" id="ticket_template_select" name="ticket_template_id">
<option value="0">- No Template -</option>
<?php
$sql_ticket_templates = mysqli_query($mysqli, "
SELECT tt.ticket_template_id,
tt.ticket_template_name,
tt.ticket_template_subject,
tt.ticket_template_details,
COUNT(ttt.task_template_id) as task_count
FROM ticket_templates tt
LEFT JOIN task_templates ttt
ON tt.ticket_template_id = ttt.task_template_ticket_template_id
WHERE (tt.ticket_template_archived_at IS NULL OR tt.ticket_template_id = $recurring_ticket_ticket_template_id)
GROUP BY tt.ticket_template_id
ORDER BY tt.ticket_template_name ASC
");
while ($row = mysqli_fetch_assoc($sql_ticket_templates)) {
$ticket_template_id_select = intval($row['ticket_template_id']);
$ticket_template_name_select = escapeHtml($row['ticket_template_name']);
$ticket_template_subject_select = escapeHtml($row['ticket_template_subject']);
$ticket_template_details_select = escapeHtml($row['ticket_template_details']);
$task_count = intval($row['task_count']);
?>
<option value="<?= $ticket_template_id_select ?>"
data-subject="<?= $ticket_template_subject_select ?>"
data-details="<?= $ticket_template_details_select ?>"
<?php if ($recurring_ticket_ticket_template_id == $ticket_template_id_select) { echo "selected"; } ?>>
<?= $ticket_template_name_select ?> (<?= $task_count ?> tasks)
</option>
<?php } ?>
</select>
</div>
<small class="form-text text-muted">The template's tasks are added to every ticket this schedule raises. Changing it rewrites the subject and details below.</small>
</div>
<div class="form-group">
<label>Subject <strong class="text-danger">*</strong></label>
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text"><i class="fa fa-fw fa-tag"></i></span>
</div>
<input type="text" class="form-control" name="subject" placeholder="Subject" maxlength="500" value="<?= $recurring_ticket_subject ?>" required >
<input type="text" class="form-control" id="subjectInput" name="subject" placeholder="Subject" maxlength="500" value="<?= $recurring_ticket_subject ?>" required >
</div>
</div>
<div class="form-group">
<textarea class="form-control tinymce" name="details"><?= $recurring_ticket_details ?></textarea>
<textarea class="form-control tinymce" id="detailsInput" name="details"><?= $recurring_ticket_details ?></textarea>
</div>
<div class="row">
@@ -306,6 +349,35 @@ ob_start();
</div>
</form>
<!-- Ticket Templates -->
<script>
$(document).on('change', '#ticket_template_select', function () {
const $opt = $(this).find(':selected');
// Selecting "- No Template -" only unlinks the template - it must not wipe
// whatever subject/details the user has already written
if (!parseInt($opt.val(), 10)) {
return;
}
const templateSubject = $opt.data('subject') || '';
const templateDetails = $opt.data('details') || '';
$('#subjectInput').val(templateSubject);
if (window.tinymce) {
const editor = tinymce.get('detailsInput');
if (editor) {
editor.setContent(templateDetails);
} else {
$('#detailsInput').val(templateDetails);
}
} else {
$('#detailsInput').val(templateDetails);
}
});
</script>
<?php
require_once '../../../includes/modal_footer.php';

View File

@@ -20,7 +20,7 @@ if (isset($_POST['add_recurring_ticket'])) {
$start_date = escapeSql($_POST['start_date']);
mysqli_query($mysqli, "INSERT INTO recurring_tickets SET recurring_ticket_subject = '$subject', recurring_ticket_details = '$details', recurring_ticket_priority = '$priority', recurring_ticket_frequency = '$frequency', recurring_ticket_billable = $billable, recurring_ticket_start_date = '$start_date', recurring_ticket_next_run = '$start_date', recurring_ticket_assigned_to = $assigned_to, recurring_ticket_created_by = $session_user_id, recurring_ticket_client_id = $client_id, recurring_ticket_contact_id = $contact_id, recurring_ticket_asset_id = $asset_id, recurring_ticket_category = $category_id");
mysqli_query($mysqli, "INSERT INTO recurring_tickets SET recurring_ticket_subject = '$subject', recurring_ticket_details = '$details', recurring_ticket_priority = '$priority', recurring_ticket_frequency = '$frequency', recurring_ticket_billable = $billable, recurring_ticket_start_date = '$start_date', recurring_ticket_next_run = '$start_date', recurring_ticket_assigned_to = $assigned_to, recurring_ticket_created_by = $session_user_id, recurring_ticket_client_id = $client_id, recurring_ticket_contact_id = $contact_id, recurring_ticket_asset_id = $asset_id, recurring_ticket_category = $category_id, recurring_ticket_ticket_template_id = $ticket_template_id");
$recurring_ticket_id = mysqli_insert_id($mysqli);
@@ -55,7 +55,7 @@ if (isset($_POST['edit_recurring_ticket'])) {
enforceClientAccess();
mysqli_query($mysqli, "UPDATE recurring_tickets SET recurring_ticket_subject = '$subject', recurring_ticket_details = '$details', recurring_ticket_priority = '$priority', recurring_ticket_frequency = '$frequency', recurring_ticket_billable = $billable, recurring_ticket_next_run = '$next_run_date', recurring_ticket_assigned_to = $assigned_to, recurring_ticket_asset_id = $asset_id, recurring_ticket_contact_id = $contact_id, recurring_ticket_category = $category_id WHERE recurring_ticket_id = $recurring_ticket_id");
mysqli_query($mysqli, "UPDATE recurring_tickets SET recurring_ticket_subject = '$subject', recurring_ticket_details = '$details', recurring_ticket_priority = '$priority', recurring_ticket_frequency = '$frequency', recurring_ticket_billable = $billable, recurring_ticket_next_run = '$next_run_date', recurring_ticket_assigned_to = $assigned_to, recurring_ticket_asset_id = $asset_id, recurring_ticket_contact_id = $contact_id, recurring_ticket_category = $category_id, recurring_ticket_ticket_template_id = $ticket_template_id WHERE recurring_ticket_id = $recurring_ticket_id");
// Add Additional Assets
if (isset($_POST['additional_assets'])) {
@@ -102,6 +102,7 @@ if (isset($_POST['bulk_force_recurring_tickets'])) {
$client_id = intval($row['recurring_ticket_client_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']);
$url_key = randomString(32);
enforceClientAccess();
@@ -139,6 +140,9 @@ if (isset($_POST['bulk_force_recurring_tickets'])) {
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);
// Notifications
triggerCustomAction('ticket_create', $id);
@@ -243,6 +247,7 @@ if (isset($_GET['force_recurring_ticket'])) {
$client_id = intval($row['recurring_ticket_client_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']);
$url_key = randomString(32);
enforceClientAccess();
@@ -280,6 +285,9 @@ if (isset($_GET['force_recurring_ticket'])) {
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);
// Notifications
triggerCustomAction('ticket_create', $id);

View File

@@ -10,3 +10,4 @@ $asset_id = intval($_POST['asset_id'] ?? 0);
$contact_id = intval($_POST['contact_id'] ?? 0);
$assigned_to = intval($_POST['assigned_to'] ?? 0);
$category_id = intval($_POST['category_id'] ?? 0);
$ticket_template_id = intval($_POST['ticket_template_id'] ?? 0);

View File

@@ -80,20 +80,7 @@ if (isset($_POST['add_ticket'])) {
applyTicketSla($ticket_id);
// Add Tasks from Template if Template was selected
if($ticket_template_id) {
// 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");
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']);
$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);