mirror of https://github.com/itflow-org/itflow
[Feature] Updated Invoice Ticket to include more details in the description, predefined along with optional Invoice Title, helper texts below qty and price to show how it gets its information, fixed ticket number not showing in ticket reply when adding ticket to an existing invoice. Add to Existing Invoice is default if open invoices exist, migrated many more ticket related modals to use ajax-modal
This commit is contained in:
parent
43a7b7faa5
commit
9fcaf9f5cc
|
|
@ -36,7 +36,4 @@ if (isset($session_is_admin) && $session_is_admin) {
|
|||
require_once "../post/logout.php";
|
||||
|
||||
// TODO: Find a home for these
|
||||
|
||||
require_once "../post/ai.php";
|
||||
require_once "../post/misc.php";
|
||||
|
||||
|
|
|
|||
244
agent/ajax.php
244
agent/ajax.php
|
|
@ -699,3 +699,247 @@ if (isset($_GET['client_duplicate_check'])) {
|
|||
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
if (isset($_GET['ai_reword'])) {
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$promptText = $row['ai_model_prompt'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
// Collecting the input data from the AJAX request.
|
||||
$inputJSON = file_get_contents('php://input');
|
||||
$input = json_decode($inputJSON, TRUE); // Convert JSON into array.
|
||||
|
||||
$userText = $input['text'];
|
||||
|
||||
// Preparing the data for the OpenAI Chat API request.
|
||||
$data = [
|
||||
"model" => "$model_name", // Specify the model
|
||||
"messages" => [
|
||||
["role" => "system", "content" => $promptText],
|
||||
["role" => "user", "content" => $userText],
|
||||
],
|
||||
"temperature" => 0.5
|
||||
];
|
||||
|
||||
// Initialize cURL session to the OpenAI Chat API.
|
||||
$ch = curl_init("$url");
|
||||
|
||||
// Set cURL options for the request.
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key,
|
||||
]);
|
||||
|
||||
// Execute the cURL session and capture the response.
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// Decode the JSON response.
|
||||
$responseData = json_decode($response, true);
|
||||
|
||||
// Check if the response contains the expected data and return it.
|
||||
if (isset($responseData['choices'][0]['message']['content'])) {
|
||||
// Get the response content.
|
||||
$content = $responseData['choices'][0]['message']['content'];
|
||||
|
||||
// Clean any leading "html" word or other unwanted text at the beginning.
|
||||
$content = preg_replace('/^html/i', '', $content); // Remove any occurrence of 'html' at the start
|
||||
|
||||
// Clean the response content to remove backticks or code block markers.
|
||||
$cleanedContent = str_replace('```', '', $content); // Remove backticks if they exist.
|
||||
|
||||
// Trim any leading/trailing whitespace.
|
||||
$cleanedContent = trim($cleanedContent);
|
||||
|
||||
// Return the cleaned response.
|
||||
echo json_encode(['rewordedText' => $cleanedContent]);
|
||||
} else {
|
||||
// Handle errors or unexpected response structure.
|
||||
echo json_encode(['rewordedText' => 'Failed to get a response from the AI API.']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['ai_create_document_template'])) {
|
||||
// get_ai_document_template.php
|
||||
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
$prompt = $_POST['prompt'] ?? '';
|
||||
|
||||
// Basic validation
|
||||
if(empty($prompt)){
|
||||
echo "No prompt provided.";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prepare prompt
|
||||
$system_message = "You are a helpful IT documentation assistant. You will create a well-structured HTML template for IT documentation based on a given prompt. Include headings, subheadings, bullet points, and possibly tables for clarity. No Lorem Ipsum, use realistic placeholders and professional language.";
|
||||
$user_message = "Create an HTML formatted IT documentation template based on the following request:\n\n\"$prompt\"\n\nThe template should be structured, professional, and useful for IT staff. Include relevant sections, instructions, prerequisites, and best practices.";
|
||||
|
||||
$post_data = [
|
||||
"model" => "$model_name",
|
||||
"messages" => [
|
||||
["role" => "system", "content" => $system_message],
|
||||
["role" => "user", "content" => $user_message]
|
||||
],
|
||||
"temperature" => 0.5
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
echo "Error: " . curl_error($ch);
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$response_data = json_decode($response, true);
|
||||
$template = $response_data['choices'][0]['message']['content'] ?? "<p>No content returned from AI.</p>";
|
||||
|
||||
// Print the generated HTML template directly
|
||||
echo $template;
|
||||
}
|
||||
|
||||
if (isset($_GET['ai_ticket_summary'])) {
|
||||
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
// Retrieve the ticket_id from POST
|
||||
$ticket_id = intval($_POST['ticket_id']);
|
||||
|
||||
// Query the database for ticket details
|
||||
$sql = mysqli_query($mysqli, "
|
||||
SELECT ticket_subject, ticket_details, ticket_source, ticket_priority, ticket_status_name, category_name
|
||||
FROM tickets
|
||||
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
|
||||
LEFT JOIN categories ON ticket_category = category_id
|
||||
WHERE ticket_id = $ticket_id
|
||||
LIMIT 1
|
||||
");
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$ticket_subject = $row['ticket_subject'];
|
||||
$ticket_details = strip_tags($row['ticket_details']); // strip HTML for cleaner prompt
|
||||
$ticket_status = $row['ticket_status_name'];
|
||||
$ticket_category = $row['category_name'];
|
||||
$ticket_source = $row['ticket_source'];
|
||||
$ticket_priority = $row['ticket_priority'];
|
||||
|
||||
// Get ticket replies
|
||||
$sql_replies = mysqli_query($mysqli, "
|
||||
SELECT ticket_reply, ticket_reply_type, user_name
|
||||
FROM ticket_replies
|
||||
LEFT JOIN users ON ticket_reply_by = user_id
|
||||
WHERE ticket_reply_ticket_id = $ticket_id
|
||||
AND ticket_reply_archived_at IS NULL
|
||||
ORDER BY ticket_reply_id ASC
|
||||
");
|
||||
|
||||
$all_replies_text = "";
|
||||
while ($reply = mysqli_fetch_assoc($sql_replies)) {
|
||||
$reply_type = $reply['ticket_reply_type'];
|
||||
$reply_text = strip_tags($reply['ticket_reply']);
|
||||
$reply_by = $reply['user_name'];
|
||||
$all_replies_text .= "\nReply Type: $reply_type Reply By: $reply_by: Reply Text: $reply_text";
|
||||
}
|
||||
|
||||
$prompt = "
|
||||
Summarize the following IT support ticket and its responses in a concise, clear, and professional manner.
|
||||
The summary should include:
|
||||
|
||||
1. Main Issue: What was the problem reported by the user?
|
||||
2. Actions Taken: What steps were taken to address the issue?
|
||||
3. Resolution or Next Steps: Was the issue resolved or is it ongoing?
|
||||
|
||||
Please ensure:
|
||||
- If there are multiple issues, summarize each separately.
|
||||
- Urgency: If the ticket or replies express urgency or escalation, highlight it.
|
||||
- Attachments: If mentioned in the ticket, note any relevant attachments or files.
|
||||
- Avoid extra explanations or unnecessary information.
|
||||
|
||||
Ticket Data:
|
||||
- Ticket Source: $ticket_source
|
||||
- Current Ticket Status: $ticket_status
|
||||
- Ticket Priority: $ticket_priority
|
||||
- Ticket Category: $ticket_category
|
||||
- Ticket Subject: $ticket_subject
|
||||
- Ticket Details: $ticket_details
|
||||
- Replies:
|
||||
$all_replies_text
|
||||
|
||||
Formatting instructions:
|
||||
- Use valid HTML tags only.
|
||||
- Use <h3> for section headers (Main Issue, Actions Taken, Resolution).
|
||||
- Use <ul><li> for bullet points under each section.
|
||||
- Do NOT wrap the output in ```html or any other code fences.
|
||||
- Do NOT include <html>, <head>, or <body>.
|
||||
- Output only the summary content in pure HTML.
|
||||
If any part of the ticket or replies is unclear or ambiguous, mention it in the summary and suggest if further clarification is needed.
|
||||
";
|
||||
|
||||
// Prepare the POST data
|
||||
$post_data = [
|
||||
"model" => "$model_name",
|
||||
"messages" => [
|
||||
["role" => "system", "content" => "Your task is to summarize IT support tickets with clear, concise details."],
|
||||
["role" => "user", "content" => $prompt]
|
||||
],
|
||||
"temperature" => 0.3
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
echo "Error: " . curl_error($ch);
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$response_data = json_decode($response, true);
|
||||
$summary = $response_data['choices'][0]['message']['content'] ?? "No summary available.";
|
||||
|
||||
|
||||
echo $summary; // nl2br to convert newlines to <br>, htmlspecialchars to prevent XSS
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ if (isset($_GET['calendar_id'])) {
|
|||
<div class="card-header py-2">
|
||||
<h3 class="card-title mt-1">Calendars</h3>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-dark btn-sm" data-toggle="modal" data-target="#addCalendarModal"><i class="fas fa-plus"></i></button>
|
||||
<button type="button" class="btn btn-dark btn-sm ajax-modal" data-modal-url="modals/calendar/calendar_add.php"><i class="fas fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
|
|
@ -82,8 +82,6 @@ if (isset($_GET['calendar_id'])) {
|
|||
<?php
|
||||
|
||||
require_once "modals/calendar/calendar_event_add.php";
|
||||
require_once "modals/calendar/calendar_add.php";
|
||||
|
||||
|
||||
//loop through IDs and create a modal for each
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM calendar_events LEFT JOIN calendars ON event_calendar_id = calendar_id $client_event_query");
|
||||
|
|
|
|||
|
|
@ -1,94 +1,55 @@
|
|||
/*
|
||||
* LISTENERS
|
||||
*/
|
||||
$(document).ready(function() {
|
||||
|
||||
// Modal loaded listener - populate client select
|
||||
const changeClientModalLoad = document.getElementById('clientChangeTicketModalLoad');
|
||||
changeClientModalLoad.addEventListener('click', function() {
|
||||
populateChangeClientModal_Clients();
|
||||
})
|
||||
// Function to load contacts for a given client
|
||||
function loadContacts(clientId) {
|
||||
if (!clientId) return;
|
||||
|
||||
// Client selected listener - populate contact select
|
||||
// We seem to have to use jQuery to listen for events, as the client input is a select2 component?
|
||||
const clientSelectDropdown = document.getElementById("changeClientSelect");
|
||||
$(clientSelectDropdown).on('select2:select', function (e) {
|
||||
let client_id = $(this).find(':selected').val();
|
||||
populateChangeClientModal_Contacts(client_id);
|
||||
var $contactSelect = $('#contact_select');
|
||||
$contactSelect.html('<option value="">Loading...</option>');
|
||||
|
||||
$.ajax({
|
||||
url: 'ajax.php',
|
||||
type: 'GET',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
get_client_contacts: 1,
|
||||
client_id: clientId
|
||||
},
|
||||
success: function(response) {
|
||||
$contactSelect.empty();
|
||||
if (response.contacts && response.contacts.length > 0) {
|
||||
$contactSelect.append('<option value="">Select a contact</option>');
|
||||
$.each(response.contacts, function(i, contact) {
|
||||
$contactSelect.append(
|
||||
$('<option>', {
|
||||
value: contact.contact_id,
|
||||
text: contact.contact_name
|
||||
})
|
||||
);
|
||||
});
|
||||
} else {
|
||||
$contactSelect.append('<option value="">No contacts found</option>');
|
||||
}
|
||||
|
||||
// Refresh Select2
|
||||
if ($.fn.select2) {
|
||||
$contactSelect.trigger('change.select2');
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
console.error('AJAX Error:', error);
|
||||
$contactSelect.html('<option value="">Failed to load contacts</option>');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Load contacts for the currently selected client when modal opens
|
||||
var initialClientId = $('#client_select').val();
|
||||
loadContacts(initialClientId);
|
||||
|
||||
// Load contacts when client changes
|
||||
$('#client_select').on('change', function() {
|
||||
var clientId = $(this).val();
|
||||
loadContacts(clientId);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
* FUNCTIONS
|
||||
*/
|
||||
|
||||
// Populate client list function
|
||||
function populateChangeClientModal_Clients() {
|
||||
|
||||
// Get current client ID
|
||||
let current_client_id = document.getElementById("client_id").value;
|
||||
|
||||
// Send a GET request to ajax.php as ajax.php?get_active_clients=true
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_active_clients: 'true'},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for clients (multiple)
|
||||
const clients = response.clients;
|
||||
|
||||
// Client dropdown already defined in listeners as clientSelectDropdown
|
||||
|
||||
// Clear dropdown
|
||||
let i, L = clientSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
clientSelectDropdown.remove(i);
|
||||
}
|
||||
clientSelectDropdown[clientSelectDropdown.length] = new Option('- Client -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
clients.forEach(client => {
|
||||
if (parseInt(current_client_id) !== parseInt(client.client_id)) {
|
||||
// Show clients returned (excluding the current client ID - we can't change a ticket client to itself)
|
||||
clientSelectDropdown[clientSelectDropdown.length] = new Option(client.client_name, client.client_id);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Populate client contact function (after a client is selected)
|
||||
function populateChangeClientModal_Contacts(client_id) {
|
||||
// Send a GET request to ajax.php as ajax.php?get_client_contacts=true&client_id=NUM
|
||||
jQuery.get(
|
||||
"ajax.php",
|
||||
{get_client_contacts: 'true', client_id: client_id},
|
||||
function(data) {
|
||||
|
||||
// If we get a response from ajax.php, parse it as JSON
|
||||
const response = JSON.parse(data);
|
||||
|
||||
// Access the data for contacts (multiple)
|
||||
const contacts = response.contacts;
|
||||
|
||||
// Contacts dropdown
|
||||
const contactSelectDropdown = document.getElementById("changeContactSelect");
|
||||
|
||||
// Clear Category dropdown
|
||||
let i, L = contactSelectDropdown.options.length - 1;
|
||||
for (i = L; i >= 0; i--) {
|
||||
contactSelectDropdown.remove(i);
|
||||
}
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option('- Contact -', '0');
|
||||
|
||||
// Populate dropdown
|
||||
contacts.forEach(contact => {
|
||||
contactSelectDropdown[contactSelectDropdown.length] = new Option(contact.contact_name, contact.contact_id);
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,17 @@
|
|||
<div class="modal" id="addCalendarModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-calendar-plus mr-2"></i>New Calendar</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
|
|
@ -35,7 +39,7 @@
|
|||
<button type="submit" name="add_calendar" class="btn btn-primary"><i class="fa fa-check mr-2"></i>Create</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -1,14 +1,20 @@
|
|||
<div class="modal" id="addRackModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$client_id = intval($_GET['client_id'] ?? 0);
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-server mr-2"></i>New Rack</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
|
||||
<form action="post.php" method="post" enctype="multipart/form-data" autocomplete="off">
|
||||
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
|
||||
|
|
@ -147,7 +153,8 @@
|
|||
<button type="submit" name="add_rack" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Create</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -1,17 +1,22 @@
|
|||
<div class="modal" id="addTicketWatcherModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-eye mr-2"></i>Adding a ticket Watcher: <strong><?php echo "$ticket_prefix$ticket_number"; ?></strong> - <?php echo $client_name; ?></h5>
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id'] ?? 0);
|
||||
$client_id = intval(getFieldById('tickets', $ticket_id, 'ticket_client_id') ?? 0);
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-eye mr-2"></i>Adding a ticket Watcher</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
<input type="hidden" name="client_id" value="<?php echo $client_id; ?>">
|
||||
<input type="hidden" name="ticket_number" value="<?php echo "$ticket_prefix$ticket_number"; ?>">
|
||||
<input type="hidden" name="watcher_notify" value="0"> <!-- Default 0 -->
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
|
|
@ -57,8 +62,7 @@
|
|||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -1,23 +1,43 @@
|
|||
<div class="modal" id="clientChangeTicketModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-people-carry mr-2"></i>Change <?php echo "$ticket_prefix$ticket_number"; ?> to another client</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="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
<div class="modal-body">
|
||||
<?php
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
$current_client_id = intval(getFieldById('tickets', $ticket_id, 'ticket_client_id'));
|
||||
$ticket_prefix = nullable_htmlentities(getFieldById('tickets', $ticket_id, 'ticket_prefix'));
|
||||
$ticket_number = nullable_htmlentities(getFieldById('tickets', $ticket_id, 'ticket_number'));
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title">
|
||||
<i class="fa fa-fw fa-people-carry mr-2"></i>
|
||||
Change <?php echo "$ticket_prefix$ticket_number"; ?> to another client
|
||||
</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="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label>New 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-users"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="new_client_id" id="changeClientSelect" required>
|
||||
<select class="form-control select2" name="new_client_id" id="client_select" required>
|
||||
<?php
|
||||
$sql_clients = mysqli_query($mysqli, "SELECT client_id, client_name FROM clients WHERE client_lead = 0 AND client_archived_at IS NULL ORDER BY client_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_clients)) {
|
||||
$client_id_select = intval($row['client_id']);
|
||||
$client_name = nullable_htmlentities($row['client_name']);
|
||||
?>
|
||||
<option value="<?= $client_id_select ?>" <?php if ($current_client_id == $client_id_select) echo 'selected'; ?>>
|
||||
<?= $client_name ?>
|
||||
</option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -28,22 +48,23 @@
|
|||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-user"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="new_contact_id" id="changeContactSelect">
|
||||
<select class="form-control select2" name="new_contact_id" id="contact_select">
|
||||
<option value="">- Select a contact -</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="submit" name="change_client_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Change</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
<button type="submit" name="change_client_ticket" class="btn btn-primary text-bold">
|
||||
<i class="fa fa-check mr-2"></i>Change
|
||||
</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal">
|
||||
<i class="fa fa-times mr-2"></i>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Ticket Change Client JS -->
|
||||
<link rel="stylesheet" href="../plugins/jquery-ui/jquery-ui.min.css">
|
||||
<script src="../plugins/jquery-ui/jquery-ui.min.js"></script>
|
||||
<script src="js/ticket_change_client.js"></script>
|
||||
<script src="/agent/js/ticket_change_client.js"></script>
|
||||
|
||||
<?php require_once '../../../includes/modal_footer.php'; ?>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,23 @@
|
|||
<div class="modal" id="editTicketVendorModal<?php echo $ticket_id; ?>" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-building mr-2"></i>Editing ticket Vendor: <strong><?php echo "$ticket_prefix$ticket_number"; ?></strong> - <?php echo $client_name; ?></h5>
|
||||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id'] ?? 0);
|
||||
|
||||
$client_id = intval(getFieldById('tickets', $ticket_id, 'ticket_client_id') ?? 0);
|
||||
$vendor_id = intval(getFieldById('tickets', $ticket_id, 'ticket_vendor_id') ?? 0);
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-building mr-2"></i>Editing ticket Vendor</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="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="ticket_id" value="<?= $ticket_id ?>">
|
||||
<div class="modal-body">
|
||||
|
||||
<div class="form-group">
|
||||
|
|
@ -24,9 +33,9 @@
|
|||
$sql_vendors = mysqli_query($mysqli, "SELECT vendor_id, vendor_name FROM vendors WHERE vendor_client_id = $client_id AND vendor_archived_at IS NULL ORDER BY vendor_name ASC");
|
||||
while ($row = mysqli_fetch_array($sql_vendors)) {
|
||||
$vendor_id_select = intval($row['vendor_id']);
|
||||
$vendor_name_select = nullable_htmlentities($row['vendor_name']);
|
||||
$vendor_name = nullable_htmlentities($row['vendor_name']);
|
||||
?>
|
||||
<option <?php if ($vendor_id == $vendor_id_select) { echo "selected"; } ?> value="<?php echo $vendor_id_select; ?>"><?php echo $vendor_name_select; ?></option>
|
||||
<option <?php if ($vendor_id == $vendor_id_select) { echo "selected"; } ?> value="<?= $vendor_id_select ?>"><?= $vendor_name ?></option>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
|
@ -42,8 +51,7 @@
|
|||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -1,37 +1,148 @@
|
|||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
|
||||
$ticket_sql = mysqli_query(
|
||||
$mysqli,
|
||||
"SELECT * FROM tickets
|
||||
LEFT JOIN clients ON ticket_client_id = client_id
|
||||
LEFT JOIN contacts ON ticket_contact_id = contact_id
|
||||
LEFT JOIN users ON ticket_assigned_to = user_id
|
||||
LEFT JOIN locations ON ticket_location_id = location_id
|
||||
LEFT JOIN assets ON ticket_asset_id = asset_id
|
||||
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
|
||||
LEFT JOIN categories ON ticket_category = category_id
|
||||
WHERE ticket_id = $ticket_id
|
||||
$access_permission_query
|
||||
LIMIT 1"
|
||||
);
|
||||
|
||||
$row = mysqli_fetch_array($ticket_sql);
|
||||
$client_id = intval($row['client_id']);
|
||||
$client_rate = floatval($row['client_rate']);
|
||||
$ticket_prefix = nullable_htmlentities($row['ticket_prefix']);
|
||||
$ticket_number = intval($row['ticket_number']);
|
||||
$ticket_category = intval($row['ticket_category']);
|
||||
$ticket_category_display = nullable_htmlentities($row['category_name']);
|
||||
$ticket_subject = nullable_htmlentities($row['ticket_subject']);
|
||||
$ticket_priority = nullable_htmlentities($row['ticket_priority']);
|
||||
$ticket_billable = intval($row['ticket_billable']);
|
||||
$ticket_onsite = intval($row['ticket_onsite']);
|
||||
|
||||
$ticket_created_at = nullable_htmlentities($row['ticket_created_at']);
|
||||
$ticket_created_by = intval($row['ticket_created_by']);
|
||||
$ticket_date = date('Y-m-d', strtotime($ticket_created_at));
|
||||
$ticket_first_response_at = nullable_htmlentities($row['ticket_first_response_at']);
|
||||
if ($ticket_first_response_at) {
|
||||
$ticket_first_response_date_time = date('Y-m-d H:i', strtotime($ticket_first_response_at));
|
||||
} else {
|
||||
$ticket_first_response_date_time = '';
|
||||
}
|
||||
$ticket_resolved_at = nullable_htmlentities($row['ticket_resolved_at']);
|
||||
if ($ticket_resolved_at) {
|
||||
$ticket_resolved_date = date('Y-m-d', strtotime($ticket_resolved_at));
|
||||
} else {
|
||||
$ticket_resolved_date = '';
|
||||
}
|
||||
|
||||
$ticket_assigned_to = intval($row['ticket_assigned_to']);
|
||||
if ($ticket_assigned_to) {
|
||||
$ticket_assigned_agent = nullable_htmlentities($row['user_name']);
|
||||
} else {
|
||||
$ticket_assigned_agent = '';
|
||||
}
|
||||
|
||||
$contact_id = intval($row['contact_id']);
|
||||
$contact_name = nullable_htmlentities($row['contact_name']);
|
||||
|
||||
$asset_id = intval($row['asset_id']);
|
||||
$asset_name = nullable_htmlentities($row['asset_name']);
|
||||
$asset_type = nullable_htmlentities($row['asset_type']);
|
||||
|
||||
$location_id = intval($row['location_id']);
|
||||
$location_name = nullable_htmlentities($row['location_name']);
|
||||
$location_address = nullable_htmlentities($row['location_address']);
|
||||
$location_city = nullable_htmlentities($row['location_city']);
|
||||
$location_state = nullable_htmlentities($row['location_state']);
|
||||
$location_zip = nullable_htmlentities($row['location_zip']);
|
||||
$location_phone = formatPhoneNumber($row['location_phone']);
|
||||
|
||||
//Get Total Ticket Time
|
||||
$ticket_total_reply_time = mysqli_query($mysqli, "SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(ticket_reply_time_worked))) AS ticket_total_reply_time FROM ticket_replies WHERE ticket_reply_archived_at IS NULL AND ticket_reply_ticket_id = $ticket_id");
|
||||
$row = mysqli_fetch_array($ticket_total_reply_time);
|
||||
$ticket_total_reply_time = nullable_htmlentities($row['ticket_total_reply_time']);
|
||||
|
||||
$sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_status LIKE 'Draft' AND invoice_client_id = $client_id ORDER BY invoice_number ASC");
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
|
||||
<div class="modal" id="addInvoiceFromTicketModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title"><i class="fa fa-fw fa-file-invoice-dollar mr-2"></i>Invoice ticket</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
</div>
|
||||
<form action="post.php" method="post" autocomplete="off">
|
||||
<input type="hidden" name="ticket_id" value="<?php echo $ticket_id; ?>">
|
||||
<div class="modal-body">
|
||||
<?php if (mysqli_num_rows($sql_invoices) > 0) { ?>
|
||||
|
||||
<ul class="nav nav-pills nav-justified mb-3">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-create-invoice"><i class="fa fa-fw fa-check mr-2"></i>Create New Invoice</a>
|
||||
<a class="nav-link active" data-toggle="pill" href="#pills-add-to-invoice"><i class="fa fa-fw fa-plus mr-2"></i>Add to Existing Invoice</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-add-to-invoice"><i class="fa fa-fw fa-plus mr-2"></i>Add to Existing Invoice</a>
|
||||
<a class="nav-link" data-toggle="pill" href="#pills-create-invoice"><i class="fa fa-fw fa-check mr-2"></i>Create New Invoice</a>
|
||||
</li>
|
||||
<?php } ?>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
<div class="tab-pane fade show active" id="pills-create-invoice">
|
||||
<?php
|
||||
|
||||
if (mysqli_num_rows($sql_invoices) > 0) { ?>
|
||||
|
||||
<div class="tab-pane fade <?php if (mysqli_num_rows($sql_invoices) > 0) { echo "active show"; } ?>" id="pills-add-to-invoice">
|
||||
<div class="form-group">
|
||||
<label>Existing Invoice</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
|
||||
</div>
|
||||
<select class="form-control" name="invoice_id">
|
||||
<option value="0">- Select an Existing Invoice -</option>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_invoices)) {
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
$invoice_scope = nullable_htmlentities($row['invoice_scope']);
|
||||
$invoice_status = nullable_htmlentities($row['invoice_status']);
|
||||
$invoice_date = nullable_htmlentities($row['invoice_date']);
|
||||
$invoice_due = nullable_htmlentities($row['invoice_due']);
|
||||
$invoice_amount = floatval($row['invoice_amount']);
|
||||
?>
|
||||
<option value="<?php echo $invoice_id; ?>"><?php echo "$invoice_prefix$invoice_number | $invoice_scope"; ?></option>
|
||||
<?php } ?>
|
||||
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<div class="tab-pane fade <?php if (mysqli_num_rows($sql_invoices) == 0) { echo "active show"; } ?>" id="pills-create-invoice">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
|
|
@ -55,7 +166,7 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
<span class="input-group-text"><i class="fa fa-fw fa-list"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="category">
|
||||
<option value="">- Category -</option>
|
||||
<option value="">- Select a Category -</option>
|
||||
<?php
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM categories WHERE category_type = 'Income' AND category_archived_at IS NULL ORDER BY category_name ASC");
|
||||
|
|
@ -70,7 +181,7 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
?>
|
||||
</select>
|
||||
<div class="input-group-append">
|
||||
<button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#addQuickCategoryIncomeModal"><i class="fas fa-fw fa-plus"></i></button>
|
||||
<button type="button" class="btn btn-secondary ajax-modal" data-modal-url="/admin/modals/category/category_add.php?category=Expense"><i class="fas fa-fw fa-plus"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -78,56 +189,23 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Scope</label>
|
||||
<label>Invoice Title</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="scope" placeholder="Quick description" value="Ticket <?php echo "$ticket_prefix$ticket_number - $ticket_subject"; ?>">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
if (mysqli_num_rows($sql_invoices) > 0) { ?>
|
||||
|
||||
<div class="tab-pane fade" id="pills-add-to-invoice">
|
||||
<div class="form-group">
|
||||
<label>Invoice</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-file-invoice-dollar"></i></span>
|
||||
</div>
|
||||
<select class="form-control" name="invoice_id">
|
||||
<option value="0">- Invoice -</option>
|
||||
<?php
|
||||
|
||||
while ($row = mysqli_fetch_array($sql_invoices)) {
|
||||
$invoice_id = intval($row['invoice_id']);
|
||||
$invoice_prefix = nullable_htmlentities($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
$invoice_scope = nullable_htmlentities($row['invoice_scope']);
|
||||
$invoice_status = nullable_htmlentities($row['invoice_status']);
|
||||
$invoice_date = nullable_htmlentities($row['invoice_date']);
|
||||
$invoice_due = nullable_htmlentities($row['invoice_due']);
|
||||
$invoice_amount = floatval($row['invoice_amount']);
|
||||
?>
|
||||
<option value="<?php echo $invoice_id; ?>"><?php echo "$invoice_prefix$invoice_number | $invoice_scope"; ?></option>
|
||||
<?php } ?>
|
||||
|
||||
<select class="form-control select2" name="scope" data-tags="true" data-placeholder="- Enter or Select an Invoice Title -">
|
||||
<option value=""></option>
|
||||
<option><?= date('F Y'); ?> Tickets</option>
|
||||
<option><?= "Ticket $ticket_prefix$ticket_number - $ticket_subject" ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Item <strong class="text-danger">*</strong></label>
|
||||
<div class="input-group">
|
||||
|
|
@ -141,7 +219,35 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
<div class="form-group">
|
||||
<label>Item Description</label>
|
||||
<div class="input-group">
|
||||
<textarea class="form-control" rows="5" name="item_description"><?php echo "# $contact_name - $asset_name - $ticket_date\nTicket $ticket_prefix$ticket_number\n$ticket_subject\nTT: $ticket_total_reply_time"; ?></textarea>
|
||||
<textarea class="form-control" rows="10" name="item_description"><?php
|
||||
// Build description text cleanly in PHP, not mixed with HTML
|
||||
$description = "#Ticket: {$ticket_prefix}{$ticket_number} - $ticket_subject\n";
|
||||
$description .= "Priority: {$ticket_priority}\n";
|
||||
$description .= "Opened at: {$ticket_date}\n";
|
||||
if ($ticket_first_response_date_time) {
|
||||
$description .= "Initial Response: {$ticket_first_response_date_time}\n";
|
||||
}
|
||||
if ($ticket_resolved_date) {
|
||||
$description .= "Resolved at: {$ticket_resolved_date}\n";
|
||||
}
|
||||
if ($ticket_assigned_agent) {
|
||||
$description .= "Agent: {$ticket_assigned_agent}\n";
|
||||
}
|
||||
if ($location_id) {
|
||||
$description .= "Location: {$location_name}\n";
|
||||
}
|
||||
if ($contact_id) {
|
||||
$description .= "Contact: {$contact_name}\n";
|
||||
}
|
||||
if ($asset_id) {
|
||||
$description .= "Asset: {$asset_name}\n";
|
||||
}
|
||||
if ($ticket_total_reply_time) {
|
||||
$description .= "Agent Time Spent: {$ticket_total_reply_time}";
|
||||
}
|
||||
|
||||
echo trim($description); // Trim any leading/trailing spaces/newlines
|
||||
?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -156,6 +262,9 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
</div>
|
||||
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="qty" value="<?php echo roundToNearest15($ticket_total_reply_time); ?>" required>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
Based off Ticket time spent <strong><?= $ticket_total_reply_time ?></strong> in 15 Min Increments rounded up.
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -170,6 +279,9 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
</div>
|
||||
<input type="text" class="form-control" inputmode="numeric" pattern="-?[0-9]*\.?[0-9]{0,2}" name="price" value="<?php echo number_format($client_rate, 2, '.', ''); ?>" required>
|
||||
</div>
|
||||
<small class="form-text text-muted">
|
||||
Based off Hourly Client rate of <strong><?= numfmt_format_currency($currency_format, $client_rate, $session_company_currency); ?></strong>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
|
@ -204,7 +316,7 @@ $sql_invoices = mysqli_query($mysqli, "SELECT * FROM invoices WHERE invoice_stat
|
|||
<button type="submit" name="add_invoice_from_ticket" class="btn btn-primary text-bold"><i class="fa fa-check mr-2"></i>Invoice</button>
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal"><i class="fa fa-times mr-2"></i>Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
|
|||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
require_once '../../../includes/modal_header.php';
|
||||
|
||||
$ticket_id = intval($_GET['ticket_id']);
|
||||
|
||||
ob_start();
|
||||
|
||||
?>
|
||||
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title" id="summaryModalTitle">Ticket Summary</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="summaryContent">
|
||||
<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Generating summary...</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
$(function() {
|
||||
$.ajax({
|
||||
url: 'ajax.php?ai_ticket_summary',
|
||||
method: 'POST',
|
||||
data: { ticket_id: <?php echo $ticket_id; ?> },
|
||||
success: function(response) {
|
||||
$('#summaryContent').html(response);
|
||||
},
|
||||
error: function() {
|
||||
$('#summaryContent').html('Error generating summary.');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
require_once '../../../includes/modal_footer.php';
|
||||
|
|
@ -59,7 +59,7 @@ ob_start();
|
|||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-arrow-right"></i></span>
|
||||
</div>
|
||||
<select class="form-control select2" name="destination" data-tags="true" data-placeholder="- Select / Input Destination -" required>
|
||||
<select class="form-control select2" name="destination" data-tags="true" data-placeholder="- Select or Enter a Destination -" required>
|
||||
<option value=""></option>
|
||||
<?php
|
||||
if ($client_id) {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,4 @@ foreach (glob("post/*.php") as $user_module) {
|
|||
require_once "../post/logout.php";
|
||||
|
||||
// TODO: Find a home for these
|
||||
|
||||
require_once "../post/ai.php";
|
||||
require_once "../post/misc.php";
|
||||
|
|
|
|||
|
|
@ -444,9 +444,8 @@ if (isset($_POST['add_ticket_watcher'])) {
|
|||
|
||||
$ticket_id = intval($_POST['ticket_id']);
|
||||
$client_id = intval($_POST['client_id']);
|
||||
$ticket_number = sanitizeInput($_POST['ticket_number']);
|
||||
$watcher_emails = preg_split("/,| |;/", $_POST['watcher_email']); // Split on comma, semicolon or space, we sanitize later
|
||||
$notify = intval($_POST['watcher_notify']);
|
||||
$notify = intval($_POST['watcher_notify'] ?? 0);
|
||||
|
||||
// Process each watcher in list
|
||||
foreach ($watcher_emails as $watcher_email) {
|
||||
|
|
@ -505,7 +504,7 @@ if (isset($_POST['add_ticket_watcher'])) {
|
|||
addToMailQueue($data);
|
||||
}
|
||||
|
||||
logAction("Ticket", "Edit", "$session_name added $watcher_email as a watcher for ticket $config_ticket_prefix$ticket_number", $client_id, $ticket_id);
|
||||
logAction("Ticket", "Edit", "$session_name added $watcher_email as a watcher for ticket $ticket_prefix$ticket_number", $client_id, $ticket_id);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -2147,6 +2146,7 @@ if (isset($_POST['add_invoice_from_ticket'])) {
|
|||
|
||||
//Get the last Invoice Number and add 1 for the new invoice number
|
||||
$invoice_number = $config_invoice_next_number;
|
||||
$invoice_prefix = sanitizeInput($config_invoice_prefix);
|
||||
$new_config_invoice_next_number = $config_invoice_next_number + 1;
|
||||
mysqli_query($mysqli, "UPDATE settings SET config_invoice_next_number = $new_config_invoice_next_number WHERE company_id = 1");
|
||||
|
||||
|
|
@ -2155,6 +2155,11 @@ if (isset($_POST['add_invoice_from_ticket'])) {
|
|||
|
||||
mysqli_query($mysqli, "INSERT INTO invoices SET invoice_prefix = '$config_invoice_prefix', invoice_number = $invoice_number, invoice_scope = '$scope', invoice_date = '$date', invoice_due = DATE_ADD('$date', INTERVAL $client_net_terms day), invoice_currency_code = '$session_company_currency', invoice_category_id = $category, invoice_status = 'Draft', invoice_url_key = '$url_key', invoice_client_id = $client_id");
|
||||
$invoice_id = mysqli_insert_id($mysqli);
|
||||
} else {
|
||||
$sql_invoice = mysqli_query($mysqli, "SELECT invoice_prefix, invoice_number FROM invoices WHERE invoice_id = $invoice_id");
|
||||
$row = mysqli_fetch_array($sql_invoice);
|
||||
$invoice_prefix = sanitizeInput($row['invoice_prefix']);
|
||||
$invoice_number = intval($row['invoice_number']);
|
||||
}
|
||||
|
||||
//Add Item
|
||||
|
|
@ -2195,9 +2200,9 @@ if (isset($_POST['add_invoice_from_ticket'])) {
|
|||
|
||||
mysqli_query($mysqli, "UPDATE tickets SET ticket_invoice_id = $invoice_id WHERE ticket_id = $ticket_id");
|
||||
|
||||
logAction("Invoice", "Create", "$session_name created invoice $config_invoice_prefix$invoice_number from Ticket $ticket_prefix$ticket_number", $client_id, $invoice_id);
|
||||
logAction("Invoice", "Create", "$session_name created invoice $invoice_prefix$invoice_number from Ticket $ticket_prefix$ticket_number", $client_id, $invoice_id);
|
||||
|
||||
flash_alert("Invoice $config_invoice_prefix$invoice_number created from ticket");
|
||||
flash_alert("Invoice $invoice_prefix$invoice_number created from ticket");
|
||||
|
||||
redirect("invoice.php?invoice_id=$invoice_id");
|
||||
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
<div class="card-header py-2">
|
||||
<h3 class="card-title mt-2"><i class="fas fa-fw fa-server mr-2"></i>Network Racks</h3>
|
||||
<div class="card-tools">
|
||||
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#addRackModal">
|
||||
<button type="button" class="btn btn-primary ajax-modal" data-modal-url="modals/rack/rack_add.php?client_id=<?= $client_id ?>">
|
||||
<i class="fas fa-plus mr-2"></i>New Rack
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -342,6 +342,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
|||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
require_once "modals/rack/rack_add.php";
|
||||
require_once "../includes/footer.php";
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ if (isset($_GET['ticket_id'])) {
|
|||
<div class="btn-toolbar">
|
||||
|
||||
<?php if ($config_module_enable_accounting && $ticket_billable == 1 && empty($invoice_id) && lookupUserPermission("module_sales") >= 2) { ?>
|
||||
<a href="#" class="btn btn-light btn-sm ml-3" href="#" data-toggle="modal" data-target="#addInvoiceFromTicketModal">
|
||||
<a href="#" class="btn btn-light btn-sm ml-3 ajax-modal" href="#" data-modal-url="modals/ticket/ticket_invoice_add.php?ticket_id=<?= $ticket_id ?>" data-modal-size="lg">
|
||||
<i class="fas fa-fw fa-file-invoice mr-2"></i>Invoice
|
||||
</a>
|
||||
<?php }
|
||||
|
|
@ -416,7 +416,7 @@ if (isset($_GET['ticket_id'])) {
|
|||
data-modal-url="modals/ticket/ticket_edit.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit mr-2"></i>Edit
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#summaryModal">
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_summary.php?ticket_id=<?= $ticket_id ?>" data-modal-size="lg">
|
||||
<i class="fas fa-fw fa-lightbulb mr-2"></i>Summarize
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#mergeTicketModal<?php echo $ticket_id; ?>">
|
||||
|
|
@ -431,15 +431,15 @@ if (isset($_GET['ticket_id'])) {
|
|||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-desktop mr-2"></i>Add Asset
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#editTicketVendorModal<?php echo $ticket_id; ?>">
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-building mr-2"></i>Add Vendor
|
||||
</a>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" data-target="#addTicketWatcherModal">
|
||||
<a class="dropdown-item ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-users mr-2"></i>Add Watcher
|
||||
</a>
|
||||
<?php } ?>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="#" data-toggle="modal" id="clientChangeTicketModalLoad" data-target="#clientChangeTicketModal">
|
||||
<a class="dropdown-item ajax-modal" href="#" id="clientChangeTicketModalLoad" data-modal-url="modals/ticket/ticket_change_client.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-people-carry mr-2"></i>Change Client
|
||||
</a>
|
||||
<?php if (lookupUserPermission("module_support") == 3) { ?>
|
||||
|
|
@ -1077,8 +1077,8 @@ if (isset($_GET['ticket_id'])) {
|
|||
<h5 class="card-title"><i class="fas fa-fw fa-eye mr-2 mt-2"></i>Watchers</h5>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm" href="#" data-toggle="modal" data-target="#addTicketWatcherModal">
|
||||
<i class="fas fa-edit"></i>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_add_watcher.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-plus"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
|
@ -1114,7 +1114,7 @@ if (isset($_GET['ticket_id'])) {
|
|||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_asset.php?id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
|
@ -1161,8 +1161,8 @@ if (isset($_GET['ticket_id'])) {
|
|||
<h5 class="card-title"><i class="fas fa-fw fa-building mr-2 mt-2"></i>Vendor</h5>
|
||||
<div class="card-tools">
|
||||
<?php if (empty($ticket_resolved_at) && lookupUserPermission("module_support") >= 2) { ?>
|
||||
<a class="btn btn-light text-secondary btn-sm" href="#" data-toggle="modal" data-target="#editTicketVendorModal<?php echo $ticket_id; ?>">
|
||||
<i class="fas fa-edit"></i>
|
||||
<a class="btn btn-light text-secondary btn-sm ajax-modal" href="#" data-modal-url="modals/ticket/ticket_edit_vendor.php?ticket_id=<?= $ticket_id ?>">
|
||||
<i class="fas fa-fw fa-edit"></i>
|
||||
</a>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
|
@ -1244,16 +1244,9 @@ if (isset($_GET['ticket_id'])) {
|
|||
|
||||
<?php
|
||||
if (lookupUserPermission("module_support") >= 2 && empty($ticket_closed_at)) {
|
||||
require_once "modals/ticket/ticket_edit_vendor.php";
|
||||
require_once "modals/ticket/ticket_add_watcher.php";
|
||||
require_once "modals/ticket/ticket_change_client.php";
|
||||
require_once "modals/ticket/ticket_edit_schedule.php";
|
||||
require_once "modals/ticket/ticket_merge.php";
|
||||
}
|
||||
|
||||
if (lookupUserPermission("module_support") >= 2 && lookupUserPermission("module_sales") >= 2 && $config_module_enable_accounting) {
|
||||
require_once "modals/ticket/ticket_invoice_add.php";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1261,25 +1254,6 @@ require_once "../includes/footer.php";
|
|||
|
||||
?>
|
||||
|
||||
<!-- Summary Modal -->
|
||||
<div class="modal fade" id="summaryModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-dark">
|
||||
<h5 class="modal-title" id="summaryModalTitle">Ticket Summary</h5>
|
||||
<button type="button" class="close text-white" data-dismiss="modal">
|
||||
<span>×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="summaryContent">
|
||||
<div class="text-center"><i class="fas fa-spinner fa-spin"></i> Generating summary...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/show_modals.js"></script>
|
||||
|
||||
<?php if (empty($ticket_closed_at)) { ?>
|
||||
|
|
@ -1297,23 +1271,6 @@ require_once "../includes/footer.php";
|
|||
|
||||
<script src="/js/pretty_content.js"></script>
|
||||
|
||||
<script>
|
||||
$('#summaryModal').on('shown.bs.modal', function (e) {
|
||||
// Perform AJAX request to get the summary
|
||||
$.ajax({
|
||||
url: 'post.php?ai_ticket_summary',
|
||||
method: 'POST',
|
||||
data: { ticket_id: <?php echo $ticket_id; ?> },
|
||||
success: function(response) {
|
||||
$('#summaryContent').html(response);
|
||||
},
|
||||
error: function() {
|
||||
$('#summaryContent').html('Error generating summary.');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="/plugins/SortableJS/Sortable.min.js"></script>
|
||||
<script>
|
||||
new Sortable(document.querySelector('table#tasks tbody'), {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,5 @@ foreach (glob("post/*.php") as $user_module) {
|
|||
require_once "../../post/logout.php";
|
||||
|
||||
// TODO: Find a home for these
|
||||
|
||||
require_once "../../post/ai.php";
|
||||
require_once "../../post/misc.php";
|
||||
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ $(document).ready(function() {
|
|||
// Show the progress indicator
|
||||
editor.setProgressState(true);
|
||||
|
||||
fetch('post.php?ai_reword', {
|
||||
fetch('ajax.php?ai_reword', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
|
@ -236,7 +236,7 @@ $(document).ready(function() {
|
|||
rewordButtonApi.setEnabled(false);
|
||||
editor.setProgressState(true);
|
||||
|
||||
fetch('post.php?ai_reword', {
|
||||
fetch('ajax.php?ai_reword', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: content }),
|
||||
|
|
|
|||
251
post/ai.php
251
post/ai.php
|
|
@ -1,251 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* ITFlow - GET/POST request handler for AI Functions
|
||||
*/
|
||||
|
||||
// TODO: Should this be moved to AJAX?
|
||||
|
||||
if (isset($_GET['ai_reword'])) {
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$promptText = $row['ai_model_prompt'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
// Collecting the input data from the AJAX request.
|
||||
$inputJSON = file_get_contents('php://input');
|
||||
$input = json_decode($inputJSON, TRUE); // Convert JSON into array.
|
||||
|
||||
$userText = $input['text'];
|
||||
|
||||
// Preparing the data for the OpenAI Chat API request.
|
||||
$data = [
|
||||
"model" => "$model_name", // Specify the model
|
||||
"messages" => [
|
||||
["role" => "system", "content" => $promptText],
|
||||
["role" => "user", "content" => $userText],
|
||||
],
|
||||
"temperature" => 0.5
|
||||
];
|
||||
|
||||
// Initialize cURL session to the OpenAI Chat API.
|
||||
$ch = curl_init("$url");
|
||||
|
||||
// Set cURL options for the request.
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key,
|
||||
]);
|
||||
|
||||
// Execute the cURL session and capture the response.
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
// Decode the JSON response.
|
||||
$responseData = json_decode($response, true);
|
||||
|
||||
// Check if the response contains the expected data and return it.
|
||||
if (isset($responseData['choices'][0]['message']['content'])) {
|
||||
// Get the response content.
|
||||
$content = $responseData['choices'][0]['message']['content'];
|
||||
|
||||
// Clean any leading "html" word or other unwanted text at the beginning.
|
||||
$content = preg_replace('/^html/i', '', $content); // Remove any occurrence of 'html' at the start
|
||||
|
||||
// Clean the response content to remove backticks or code block markers.
|
||||
$cleanedContent = str_replace('```', '', $content); // Remove backticks if they exist.
|
||||
|
||||
// Trim any leading/trailing whitespace.
|
||||
$cleanedContent = trim($cleanedContent);
|
||||
|
||||
// Return the cleaned response.
|
||||
echo json_encode(['rewordedText' => $cleanedContent]);
|
||||
} else {
|
||||
// Handle errors or unexpected response structure.
|
||||
echo json_encode(['rewordedText' => 'Failed to get a response from the AI API.']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (isset($_GET['ai_ticket_summary'])) {
|
||||
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
// Retrieve the ticket_id from POST
|
||||
$ticket_id = intval($_POST['ticket_id']);
|
||||
|
||||
// Query the database for ticket details
|
||||
$sql = mysqli_query($mysqli, "
|
||||
SELECT ticket_subject, ticket_details, ticket_source, ticket_priority, ticket_status_name, category_name
|
||||
FROM tickets
|
||||
LEFT JOIN ticket_statuses ON ticket_status = ticket_status_id
|
||||
LEFT JOIN categories ON ticket_category = category_id
|
||||
WHERE ticket_id = $ticket_id
|
||||
LIMIT 1
|
||||
");
|
||||
$row = mysqli_fetch_assoc($sql);
|
||||
$ticket_subject = $row['ticket_subject'];
|
||||
$ticket_details = strip_tags($row['ticket_details']); // strip HTML for cleaner prompt
|
||||
$ticket_status = $row['ticket_status_name'];
|
||||
$ticket_category = $row['category_name'];
|
||||
$ticket_source = $row['ticket_source'];
|
||||
$ticket_priority = $row['ticket_priority'];
|
||||
|
||||
// Get ticket replies
|
||||
$sql_replies = mysqli_query($mysqli, "
|
||||
SELECT ticket_reply, ticket_reply_type, user_name
|
||||
FROM ticket_replies
|
||||
LEFT JOIN users ON ticket_reply_by = user_id
|
||||
WHERE ticket_reply_ticket_id = $ticket_id
|
||||
AND ticket_reply_archived_at IS NULL
|
||||
ORDER BY ticket_reply_id ASC
|
||||
");
|
||||
|
||||
$all_replies_text = "";
|
||||
while ($reply = mysqli_fetch_assoc($sql_replies)) {
|
||||
$reply_type = $reply['ticket_reply_type'];
|
||||
$reply_text = strip_tags($reply['ticket_reply']);
|
||||
$reply_by = $reply['user_name'];
|
||||
$all_replies_text .= "\nReply Type: $reply_type Reply By: $reply_by: Reply Text: $reply_text";
|
||||
}
|
||||
|
||||
$prompt = "
|
||||
Summarize the following IT support ticket and its responses in a concise, clear, and professional manner.
|
||||
The summary should include:
|
||||
|
||||
1. Main Issue: What was the problem reported by the user?
|
||||
2. Actions Taken: What steps were taken to address the issue?
|
||||
3. Resolution or Next Steps: Was the issue resolved or is it ongoing?
|
||||
|
||||
Please ensure:
|
||||
- If there are multiple issues, summarize each separately.
|
||||
- Urgency: If the ticket or replies express urgency or escalation, highlight it.
|
||||
- Attachments: If mentioned in the ticket, note any relevant attachments or files.
|
||||
- Avoid extra explanations or unnecessary information.
|
||||
|
||||
Ticket Data:
|
||||
- Ticket Source: $ticket_source
|
||||
- Current Ticket Status: $ticket_status
|
||||
- Ticket Priority: $ticket_priority
|
||||
- Ticket Category: $ticket_category
|
||||
- Ticket Subject: $ticket_subject
|
||||
- Ticket Details: $ticket_details
|
||||
- Replies:
|
||||
$all_replies_text
|
||||
|
||||
Formatting instructions:
|
||||
- Use valid HTML tags only.
|
||||
- Use <h3> for section headers (Main Issue, Actions Taken, Resolution).
|
||||
- Use <ul><li> for bullet points under each section.
|
||||
- Do NOT wrap the output in ```html or any other code fences.
|
||||
- Do NOT include <html>, <head>, or <body>.
|
||||
- Output only the summary content in pure HTML.
|
||||
If any part of the ticket or replies is unclear or ambiguous, mention it in the summary and suggest if further clarification is needed.
|
||||
";
|
||||
|
||||
// Prepare the POST data
|
||||
$post_data = [
|
||||
"model" => "$model_name",
|
||||
"messages" => [
|
||||
["role" => "system", "content" => "Your task is to summarize IT support tickets with clear, concise details."],
|
||||
["role" => "user", "content" => $prompt]
|
||||
],
|
||||
"temperature" => 0.3
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
echo "Error: " . curl_error($ch);
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$response_data = json_decode($response, true);
|
||||
$summary = $response_data['choices'][0]['message']['content'] ?? "No summary available.";
|
||||
|
||||
|
||||
echo $summary; // nl2br to convert newlines to <br>, htmlspecialchars to prevent XSS
|
||||
}
|
||||
|
||||
if (isset($_GET['ai_create_document_template'])) {
|
||||
// get_ai_document_template.php
|
||||
|
||||
header('Content-Type: text/html; charset=UTF-8');
|
||||
|
||||
$sql = mysqli_query($mysqli, "SELECT * FROM ai_models LEFT JOIN ai_providers ON ai_model_ai_provider_id = ai_provider_id WHERE ai_model_use_case = 'General' LIMIT 1");
|
||||
|
||||
$row = mysqli_fetch_array($sql);
|
||||
$model_name = $row['ai_model_name'];
|
||||
$url = $row['ai_provider_api_url'];
|
||||
$key = $row['ai_provider_api_key'];
|
||||
|
||||
$prompt = $_POST['prompt'] ?? '';
|
||||
|
||||
// Basic validation
|
||||
if(empty($prompt)){
|
||||
echo "No prompt provided.";
|
||||
exit;
|
||||
}
|
||||
|
||||
// Prepare prompt
|
||||
$system_message = "You are a helpful IT documentation assistant. You will create a well-structured HTML template for IT documentation based on a given prompt. Include headings, subheadings, bullet points, and possibly tables for clarity. No Lorem Ipsum, use realistic placeholders and professional language.";
|
||||
$user_message = "Create an HTML formatted IT documentation template based on the following request:\n\n\"$prompt\"\n\nThe template should be structured, professional, and useful for IT staff. Include relevant sections, instructions, prerequisites, and best practices.";
|
||||
|
||||
$post_data = [
|
||||
"model" => "$model_name",
|
||||
"messages" => [
|
||||
["role" => "system", "content" => $system_message],
|
||||
["role" => "user", "content" => $user_message]
|
||||
],
|
||||
"temperature" => 0.5
|
||||
];
|
||||
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, $url);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type: application/json',
|
||||
'Authorization: Bearer ' . $key
|
||||
]);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
|
||||
|
||||
$response = curl_exec($ch);
|
||||
if (curl_errno($ch)) {
|
||||
echo "Error: " . curl_error($ch);
|
||||
exit;
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$response_data = json_decode($response, true);
|
||||
$template = $response_data['choices'][0]['message']['content'] ?? "<p>No content returned from AI.</p>";
|
||||
|
||||
// Print the generated HTML template directly
|
||||
echo $template;
|
||||
}
|
||||
Loading…
Reference in New Issue