mirror of
https://github.com/itflow-org/itflow
synced 2026-08-05 07:07:14 +00:00
Add optional ticket SLAs
Response/resolution targets stamped at creation from per-client/priority assignments, business-hours due date math, warn/breach alert stages via cron/ticket_sla.php, ticket list coloring, per-ticket SLA override, admin page for plans/assignments/business hours. DB update 2.5.0. No behavior change unless SLAs are assigned. Bulk reply now only counts Public replies as first response.
This commit is contained in:
64
admin/modals/sla/sla_add.php
Normal file
64
admin/modals/sla/sla_add.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
require_once '../../includes/modal_header.php';
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-stopwatch mr-2"></i>New SLA</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>Name <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-stopwatch"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" placeholder="SLA name" maxlength="200" required autofocus>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Description</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-comment"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="description" placeholder="Short description" maxlength="500">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Response target (business minutes) <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-reply"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="response_minutes" min="1" placeholder="e.g. 60" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Resolution target (business minutes)</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-flag-checkered"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="resolution_minutes" min="1" placeholder="Leave empty for response-only">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="add_sla" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Create</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
85
admin/modals/sla/sla_assignment_client.php
Normal file
85
admin/modals/sla/sla_assignment_client.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
require_once '../../includes/modal_header.php';
|
||||
|
||||
// With a client_id we're editing that client's overrides, otherwise adding new
|
||||
$client_id = intval($_GET['client_id'] ?? 0);
|
||||
|
||||
$client_name = '';
|
||||
$client_assignments = [];
|
||||
if ($client_id) {
|
||||
$client_row = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT client_name FROM clients WHERE client_id = $client_id LIMIT 1"));
|
||||
$client_name = escapeHtml($client_row['client_name']);
|
||||
|
||||
$sql_assignments = mysqli_query($mysqli, "SELECT sla_assignment_priority, sla_assignment_sla_id FROM sla_assignments WHERE sla_assignment_client_id = $client_id");
|
||||
while ($assignment_row = mysqli_fetch_assoc($sql_assignments)) {
|
||||
$client_assignments[$assignment_row['sla_assignment_priority']] = intval($assignment_row['sla_assignment_sla_id']);
|
||||
}
|
||||
}
|
||||
|
||||
$sql_slas = mysqli_query($mysqli, "SELECT sla_id, sla_name FROM slas WHERE sla_archived_at IS NULL ORDER BY sla_name ASC");
|
||||
$active_slas = [];
|
||||
while ($sla_row = mysqli_fetch_assoc($sql_slas)) {
|
||||
$active_slas[intval($sla_row['sla_id'])] = $sla_row['sla_name'];
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-random mr-2"></i><?= $client_id ? "Editing SLA overrides: <strong>$client_name</strong>" : "New client SLA override" ?></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
<label>Client <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-user"></i></span>
|
||||
</div>
|
||||
<?php if ($client_id) { ?>
|
||||
<input type="hidden" name="client_id" value="<?= $client_id ?>">
|
||||
<input type="text" class="form-control" value="<?= $client_name ?>" disabled>
|
||||
<?php } else { ?>
|
||||
<select class="form-control select2" name="client_id" required>
|
||||
<option value="">- Client -</option>
|
||||
<?php
|
||||
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_archived_at IS NULL ORDER BY client_name ASC");
|
||||
while ($client_row = mysqli_fetch_assoc($sql_clients)) { ?>
|
||||
<option value="<?= intval($client_row['client_id']) ?>"><?= escapeHtml($client_row['client_name']) ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
<?php } ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php foreach (['Low', 'Medium', 'High'] as $priority) {
|
||||
$current = $client_assignments[$priority] ?? 'default';
|
||||
?>
|
||||
<div class="form-group">
|
||||
<label><?= $priority ?> priority</label>
|
||||
<select class="form-control" name="client_sla_<?= strtolower($priority) ?>">
|
||||
<option value="default" <?php if ($current === 'default') { echo "selected"; } ?>>Default (follow global)</option>
|
||||
<option value="0" <?php if ($current === 0) { echo "selected"; } ?>>None (no SLA)</option>
|
||||
<?php foreach ($active_slas as $active_sla_id => $active_sla_name) { ?>
|
||||
<option value="<?= $active_sla_id ?>" <?php if ($current === $active_sla_id) { echo "selected"; } ?>><?= escapeHtml($active_sla_name) ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="save_client_sla_assignment" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
76
admin/modals/sla/sla_edit.php
Normal file
76
admin/modals/sla/sla_edit.php
Normal file
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
require_once '../../includes/modal_header.php';
|
||||
|
||||
$sla_id = intval($_GET['id']);
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM slas WHERE sla_id = $sla_id LIMIT 1");
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$sla_name = escapeHtml($row['sla_name']);
|
||||
$sla_description = escapeHtml($row['sla_description']);
|
||||
$sla_response_minutes = intval($row['sla_response_minutes']);
|
||||
$sla_resolution_minutes = intval($row['sla_resolution_minutes']);
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fas fa-fw fa-stopwatch mr-2"></i>Editing SLA: <strong><?= $sla_name ?></strong></h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="csrf_token" value="<?= $_SESSION['csrf_token'] ?>">
|
||||
<input type="hidden" name="sla_id" value="<?= $sla_id ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>Name <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-stopwatch"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="name" value="<?= $sla_name ?>" maxlength="200" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Description</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-comment"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="description" value="<?= $sla_description ?>" maxlength="500">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Response target (business minutes) <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-reply"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="response_minutes" min="1" value="<?= $sla_response_minutes ?>" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Resolution target (business minutes)</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-flag-checkered"></i></span>
|
||||
</div>
|
||||
<input type="number" class="form-control" name="resolution_minutes" min="1" value="<?= $sla_resolution_minutes ?: '' ?>" placeholder="Leave empty for response-only">
|
||||
</div>
|
||||
<small class="text-muted">Saving recalculates targets on open tickets using this SLA.</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="edit_sla" class="btn btn-primary text-bold"><i class="fas fa-check mr-2"></i>Save</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fas fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
Reference in New Issue
Block a user