'ticket templates', 'title' => 'That ticket template is gone', 'text' => 'It may have been deleted.', 'icon' => 'fa-life-ring', 'filtered' => false, 'actions' => [['label' => 'Ticket Templates', 'href' => 'ticket_templates.php']]]); require_once "../includes/footer.php"; exit(); } $ticket_template_id = intval($template['ticket_template_id']); $name = escapeHtml($template['ticket_template_name']); $archived = !empty($template['ticket_template_archived_at']); $tasks = ticketTemplateTasks($ticket_template_id); $task_minutes = array_sum(array_column($tasks, 'estimate')); $tag_ids = ticketTemplateTagIds($ticket_template_id); $tag_rows = []; if ($tag_ids) { $sql = mysqli_query($mysqli, "SELECT * FROM tags WHERE tag_id IN (" . implode(',', $tag_ids) . ") ORDER BY tag_name"); while ($row = mysqli_fetch_assoc($sql)) { $tag_rows[] = $row; } } $usage = ticketTemplateUsage([$ticket_template_id])[$ticket_template_id] ?? ['count' => 0, 'open' => 0, 'last' => null]; $csrf = $_SESSION['csrf_token']; // The tickets it raised most lately $recent = []; $sql = mysqli_query($mysqli, "SELECT ticket_id, ticket_prefix, ticket_number, ticket_subject, ticket_client_id, ticket_created_at, ticket_resolved_at, ticket_closed_at, client_name, ticket_status_name, ticket_status_color FROM tickets LEFT JOIN clients ON client_id = ticket_client_id LEFT JOIN ticket_statuses ON ticket_status_id = ticket_status WHERE ticket_template_id = $ticket_template_id AND ticket_archived_at IS NULL ORDER BY ticket_created_at DESC, ticket_id DESC LIMIT 8"); while ($row = mysqli_fetch_assoc($sql)) { $recent[] = $row; } // What raises it $recurring = []; $sql = mysqli_query($mysqli, "SELECT recurring_ticket_id, recurring_ticket_subject, recurring_ticket_frequency, recurring_ticket_client_id, client_name FROM recurring_tickets LEFT JOIN clients ON client_id = recurring_ticket_client_id WHERE recurring_ticket_ticket_template_id = $ticket_template_id ORDER BY client_name, recurring_ticket_subject"); while ($row = mysqli_fetch_assoc($sql)) { $recurring[] = $row; } $projects = []; $sql = mysqli_query($mysqli, "SELECT project_templates.project_template_id, project_template_name FROM project_template_ticket_templates JOIN project_templates ON project_templates.project_template_id = project_template_ticket_templates.project_template_id WHERE project_template_ticket_templates.ticket_template_id = $ticket_template_id ORDER BY project_template_name"); while ($row = mysqli_fetch_assoc($sql)) { $projects[] = $row; } // Its placeholders - filled in from the ticket - and what it asks for: its fill-ins $known = array_map('strtolower', array_keys(TICKET_PLACEHOLDERS)); $found = ticketTemplatePlaceholdersIn($template['ticket_template_subject'] . ' ' . $template['ticket_template_details'] . ' ' . implode(' ', array_column($tasks, 'name'))); $filled = array_values(array_filter($found, function ($word) use ($known) { return in_array(strtolower($word), $known, true); })); $fill_ins = ticketTemplateFillIns($template, $tasks, ticketTemplateFillInRowsFor([$ticket_template_id])[$ticket_template_id]); $when_select = ticketTemplateWhenSelectHtml($fill_ins); // [Words] marked where they appear - escaped text, or HTML already made safe. Fill-ins in blue. $mark = function ($html) use ($known) { return preg_replace_callback('/\[(' . TICKET_PLACEHOLDER_NAME . ')\]/', function ($match) use ($known) { $tone = in_array(strtolower(trim($match[1])), $known, true) ? 'text-bg-light border' : 'text-primary-emphasis bg-primary-subtle border border-primary-subtle'; return '[' . $match[1] . ']'; }, $html); }; $fill_in_url = "modals/ticket_template/ticket_template_fill_in.php?ticket_template_id=$ticket_template_id"; // Its request form in the client portal - who sees it, and what it has raised $portal = intval($template['ticket_template_portal']) === 1; $portal_clients = []; if ($portal && !intval($template['ticket_template_portal_all_clients'])) { $sql = mysqli_query($mysqli, "SELECT clients.client_id, client_name FROM ticket_template_portal_clients JOIN clients ON clients.client_id = ticket_template_portal_clients.client_id WHERE ticket_template_id = $ticket_template_id ORDER BY client_name"); while ($row = mysqli_fetch_assoc($sql)) { $portal_clients[] = $row; } } $portal_requests = ticketTemplatePortalRequests([$ticket_template_id])[$ticket_template_id] ?? 0; $asks_client = count(array_filter($fill_ins, function ($fill_in) { return $fill_in['client']; })); $details = trim((string) $template['ticket_template_details']) !== '' ? $mark(documentHtmlPurify($template['ticket_template_details'])) : ''; $edit_url = "modals/ticket_template/ticket_template_edit.php?id=$ticket_template_id"; ?>

Archived - not offered for new tickets

The ticket it starts

Subject
None - typed in on New Ticket' ?>
Details
None' ?>

Fill-ins

Asked for when a ticket is raised from it - on New Ticket, the New Tickets windows and recurring tickets - and kept on the ticket. Each answer goes in wherever its [Name] is. Drag to change the order they are asked in.

Required Agents only Not in the text
Nothing to ask. Put a word in square brackets in the subject, details or a task - [Employee Name], [Start Date] - and it is asked for when a ticket is raised from it, then filled in. Add one here to make it a date, a choice from a list or yes or no, or to make it required.

Tasks

task' . escapeHtml(ticketTemplateMinutesText($task_minutes)) : '' ?>
$task) { ?>
No tasks yet. A ticket raised from it gets a copy of each, in this order - and later changes here don't touch tickets already raised. A task can be for one answer only - "Order a laptop" when Needs a laptop is Yes.

Sets up

As it is'; $set_up = [ 'Category' => intval($template['ticket_template_category_id']) && !empty($template['category_name']) ? categoryChip(['category_name' => $template['category_name'], 'category_type' => 'Ticket', 'category_color' => $template['category_color'], 'category_icon' => $template['category_icon']]) : $leave, 'Priority' => !empty($template['ticket_template_priority']) ? ticketPriorityHtml($template['ticket_template_priority'], 'detail') : $leave, 'Assign to' => intval($template['ticket_template_assigned_to']) && !empty($template['assignee_name']) ? userAvatar($template['ticket_template_assigned_to'], $template['assignee_name'], $template['assignee_avatar'] ?? '', 'sm') . ' ' . escapeHtml($template['assignee_name']) : $leave, 'Due' => intval($template['ticket_template_due_hours']) ? escapeHtml(ticketTemplateDueText($template['ticket_template_due_hours'])) . ' after it is raised' : 'No due date', ]; if (!empty($config_module_enable_accounting)) { $set_up['Billable'] = $template['ticket_template_billable'] === null ? $leave : (intval($template['ticket_template_billable']) ? 'Billable' : 'Not billable'); } $set_up['Tags'] = $tag_rows ? '' . implode('', array_map('tagPill', $tag_rows)) . '' : 'None'; ?>
$value) { ?>

Client portal

Who
At
Every client ' . escapeHtml($row['client_name']) . ''; }, $portal_clients)) ?: 'No client' ?>
Asks
Requests
Archived - not offered until it is restored
Not offered there. Offer it as a request form and clients answer what it asks - the ticket is raised set up as it says, with its tasks.

Placeholders

Filled in from the ticket
[]

Used

ticket raised' . $usage['open'] . ' still open' : '' ?> - last
No tickets raised from it yet - counting started with this version of ITFlow.
Raised by
  • -
  • - project template