diff --git a/CHANGELOG.md b/CHANGELOG.md index d35ccc2f..10370d33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,102 @@ This file documents all notable changes made to ITFlow. +## [25.11] Changelog + +### Deprecation Notice: +- **Outdated CRON Scripts**: The following scripts are removed. + - `/scripts/cron_mail_queue.php` + - `/scripts/cron_ticket_email_parser.php` + - `/scripts/cron.php` + - `/scripts/cron_domain_refresher.php` + - `/scripts/cron_certificate_refresher.php` + + **Action Required**: Transition to the new versions: + - `/cron/mail_queue.php` + - `/cron/ticket_email_parser.php` + - `/cron/cron.php` + - `/cron/domain_refresher.php` + - `/cron/certificate_refresher.php` + +- PHP Extensions php-imap and php-mime-mail-parser are no longer required. +--- + +### Fixes +- **Ticket Listing**: Resolved issue where the “Check All” checkbox was visible even when ticket status wasn’t set. Now hidden for closed tickets only. +- **Timer Auto-Start**: Show H/M/S placeholders when timer auto-start is disabled. +- **Ticket Guest URL**: Fixed email not including the ticket guest URL key. +- **EML Generation**: Resolved issue with EML not being generated in the new ticket parser. +- **New Ticket Mail Notification**: Included message when notifying the tech of a reply in the new ticket mail parser. +- **Advanced Filter Collapse**: Added clause to prevent collapse of advanced filters when the “from” date is set to the default (1970-01-01). +- **Recurring Invoice**: Fixed issue where email was marked as sent but not actually sent when forcing a recurring invoice to an invoice. +- **CSRF Token**: Fixed issue with deleting recurring ticket from asset details page due to missing CSRF check token. +- **Vendor Website Link**: Fixed missing `https://` prefix in the vendor website link on the vendor details modal. +- **Agent Select Box**: Resolved issue where agents sometimes didn’t appear in the agent select boxes. +- **TinyMCE**: Fixed TinyMCE editor issue on Bulk Create Ticket in Assets. +- **Ticket Timer**: Fixed ticket timer initialization after reload and when the tab is put to sleep (background tab). +- **Client Deletion**: Fixed issue with client deletion. +- **Domain Records**: Added flag for missing SOA record when adding a domain (prevents subdomain creation). +- **Domain Fetching**: Quits domain record fetching if no SOA record exists (prevents subdomains). +- **Domain Expiry**: Only show time to expiry when there’s an expiry date set; otherwise, display a dash. +- **Certificates**: Improved handling of empty date in the agent UI. +- **Certificates API**: Fixed bug with missing JS to fetch certificate details. +- **API Updates**: + - Clients API: Added support for archiving/un-archiving clients, updating client data, and abbreviation support. + - Contacts API: Added archiving/un-archiving and restriction to only allow one primary contact per client. + - Mail Queue: Added recipient domain MX validation before sending emails. + +--- + +### Added / Changed +- **Backup / Restore**: Improved backup and restore by streaming data to disk (to prevent memory issues), setting unlimited timeouts, checking for bad backup contents, and using PHP for DB import instead of shell exec. Added `.htaccess` to prevent PHP execution in `/uploads/` directory. +- **Ajax Modals**: Migrated all Add and Bulk modals to the new Ajax Modal for improved performance. +- **Recurring Ticket Sorting**: Default sorting of recurring tickets by `RunDate` instead of subject. +- **Recurring Ticket Enhancements**: + - Added Billable column. + - Added bulk actions for setting priority, agent, billable status, and next run dates. + - Added filters for category, assigned agent, and billable status. + - Added new frequency options: 3-day and biweekly. +- **Asset Select**: Updated asset select dropdown to separate asset types using opt groups (planned for wider use). +- **Expiring Domains & Certificates**: Added "30 Day" warning for expiring domains and certificates in the dashboard. +- **Ticket Search**: Allowed search using both ticket prefix and number. +- **Recurring Invoice**: Cancel recurring invoices when the associated client is archived. +- **Credentials Import/Export**: Now includes TOTP secrets when importing/exporting credentials. +- **Asset Notes Import**: Allowed importing of asset notes. +- **Ticket View**: Added a "View HTML Code" button in all ticket views for TinyMCE. +- **Date Range Picker**: Updated all date filters to use the improved DateRangePicker JS. +- **Bulk Ticket Creation**: Added bulk ticket creation for clients. +- **Sidebar Updates**: Updated all sidebars to use absolute paths for easier integration with custom code. +- **Document Actions**: Added Archive and Delete buttons to the Document Details view with improved redirect behavior. +- **Ticket Template Sorting**: Allowed sorting by task count in ticket templates. +- **Contact Modal UI**: Updated contact details modal to display contact information at the top. +- **API & Code Updates**: + - Separated out post files for recurring tickets, invoices, expenses, and payments. + - Removed unused budget code. +- **Invoice Product Autocomplete**: Now allows searching for product codes as well as names. +- **Client Duplicate Check**: Flags duplicate clients or leads when using the client add modal. +- **Recurring Invoice Reference**: Added a column to invoices indicating if they were created from a recurring invoice. +- **Global Search Enhancements**: + - Allowed ticket details to be searchable in global search. + - Allowed searching for quotes in global search. +- **UI/UX Improvements**: + - Spruced up the ticket details page UI. + - Added contact email validation to flag duplicates or invalid addresses. +- **API Debugging**: Log API endpoint/URL path for authentication failures to aid in debugging. +- **Image Upload Optimization**: Removed image optimization from uploads (this will be handled by a cron job in the future). +- **View Behavior Change**: Updated ticket/invoice/quote views to always be in the Client section, showing client-side navigation and top info bar. + +--- + +### Library Updates: +- **DataTable**: Bumped from 2.3.3 to 2.3.4. +- **TinyMCE**: Bumped from 8.0.2 to 8.2.0. +- **Stripe-PHP**: Bumped from 17.6.0 to 18.1.0. +- **PHPMailer**: Bumped from 6.10.0 to 7.0.0. +- **Chart.js**: Bumped from 4.5.0 to 4.5.1. + + + + ## [25.10.1] - Deprecation Notice: `/scripts/cron_mail_queue.php` , `/scripts/cron_ticket_email_parser.php` , `/scripts/cron.php` `/scripts/cron_domain_refresher.php`, `/scripts/cron_certificate_refresher.php` are being phased out. Please transition to `/cron/mail_queue.php` , `/cron/ticket_email_parser.php`, `/cron/cron.php`, `/cron/domain_refresher.php`, `/cron/certificate_refresher.php` These older scripts will be removed in the November 25.11 release—update accordingly. 25.10.1 installs have the script already configured. diff --git a/admin/ai_model.php b/admin/ai_model.php index cca1f863..a231ce5c 100644 --- a/admin/ai_model.php +++ b/admin/ai_model.php @@ -16,7 +16,7 @@ $num_rows = mysqli_num_rows($sql);
| Template Name | +Type | +Update Frequency | +SLA (L/M/H Response) | +SLA (L/M/H Resolution) | +Hourly Rate | +After Hours Rate | +Support Hours | +Net Terms | +Created | +Updated | +Action | +
|---|---|---|---|---|---|---|---|---|---|---|---|
| + + + + + | ++ | + | + | + | + | + | + | + | + | + |
+
+
+
+
+
+ Edit
+
+
+
+ Delete
+
+
+ |
+
| + + Module + + | +Action | +
|---|---|
|
+ 6) { ?> class="ajax-modal" data-modal-url="modals/modules/module_edit.php?id== $module_id ?>" >
+ = $module_name ?>
+
+ = $module_description ?>
+ |
+
+ 6) { ?>
+
+
+ N/A Predefined"; } ?>
+
+
+
+ Edit
+
+
+
+
+ Delete
+
+
+
+ |
+
| - - Name - - | -- - Percent - - | -Action | -
|---|---|---|
| - - - - | -- |
-
-
-
-
- Edit
-
-
-
- Archive
-
-
- |
-
| + + Name + + | ++ + Percent + + | +Action | +
|---|---|---|
| + + + + | ++ |
+
+
+
+
+ Edit
+
+
+
+ Archive
+
+
+ |
+
| - + Template | -Tasks | ++ + Tasks + + | Action | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | += $task_count ?> |
Nothing to see hereGo Back"; + require_once "../includes/footer.php"; + exit(); +} + +$row = mysqli_fetch_array($sql_ticket_template); $ticket_template_name = nullable_htmlentities($row['ticket_template_name']); $ticket_template_description = nullable_htmlentities($row['ticket_template_description']); diff --git a/admin/users.php b/admin/users.php index 08feccfa..58a69210 100644 --- a/admin/users.php +++ b/admin/users.php @@ -26,16 +26,16 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));Users
-
-
- - Vendor Templates --
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
+
+
+
+ + Vendor Templates ++
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
Accounts
-
@@ -123,6 +123,4 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
'success']);
exit;
}
+
+if (isset($_GET['client_duplicate_check'])) {
+ enforceUserPermission('module_client', 2);
+
+ $name = sanitizeInput($_GET['name']);
+
+ $response['message'] = ""; // default
+
+ if (strlen($name) >= 5) {
+ $sql_clients = mysqli_query($mysqli, "SELECT client_name FROM clients
+ WHERE client_archived_at IS NULL
+ AND client_name LIKE '%$name%'
+ ORDER BY client_id DESC LIMIT 1"
+ );
+
+ if (mysqli_num_rows($sql_clients) > 0) {
+ while ($row = mysqli_fetch_array($sql_clients)) {
+ $response['message'] = " Potential duplicate: " . nullable_htmlentities($row['client_name']) . " already exists.";
+ }
+ }
+ }
+
+ echo json_encode($response);
+}
+
+if (isset($_GET['contact_email_check'])) {
+ enforceUserPermission('module_client', 2);
+
+ $email = sanitizeInput($_GET['email']);
+ $domain = sanitizeInput(substr($_GET['email'], strpos($_GET['email'], '@') + 1));
+
+ $response['message'] = ""; // default
+
+ if (strlen($email) >= 3) {
+
+ // 1. Duplicate check
+ $sql_contacts = mysqli_query($mysqli, "SELECT contact_email FROM contacts WHERE contact_email = '$email' LIMIT 1");
+ if (mysqli_num_rows($sql_contacts) > 0) {
+ while ($row = mysqli_fetch_array($sql_contacts)) {
+ $response['message'] = " Potential duplicate: " . nullable_htmlentities($row['contact_email']) . " already exists.";
+ }
+ }
+
+ // 2. MX record check
+ if (!checkdnsrr($domain, 'MX')) {
+ $response['message'] = " E-mail domain invalid.";
+ }
+
+ }
+
+ 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'] ?? "No content returned from AI. "; + + // 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 for section headers (Main Issue, Actions Taken, Resolution).
+ - Use , htmlspecialchars to prevent XSS +} + +// Stops people trying to use sub-domains in the domains tracker +if (isset($_GET['apex_domain_check'])) { + enforceUserPermission('module_support', 2); + + $domain = sanitizeInput($_GET['domain']); + + $response['message'] = ""; // default + + if (strlen($domain) >= 4) { + + // SOA record check + // This isn't 100%, as sub-domains can have their own SOA but will capture 99% + if (!checkdnsrr($domain, 'SOA')) { + $response['message'] = " Domain name is invalid."; + } + + } + + echo json_encode($response); +} diff --git a/agent/asset_details.php b/agent/asset_details.php index ac4ec904..8a5848ca 100644 --- a/agent/asset_details.php +++ b/agent/asset_details.php @@ -4,7 +4,7 @@ if (isset($_GET['client_id'])) { require_once "includes/inc_all_client.php"; $client_query = "AND asset_client_id = $client_id"; - $client_url = "AND client_id=$client_id&"; + $client_url = "client_id=$client_id&"; } else { require_once "includes/inc_client_overview_all.php"; $client_query = ''; @@ -21,525 +21,649 @@ if (isset($_GET['asset_id'])) { LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_id = $asset_id $client_query + LIMIT 1 "); - $row = mysqli_fetch_array($sql); - $client_id = intval($row['client_id']); - $client_name = nullable_htmlentities($row['client_name']); - $asset_id = intval($row['asset_id']); - $asset_type = nullable_htmlentities($row['asset_type']); - $asset_name = nullable_htmlentities($row['asset_name']); - $asset_description = nullable_htmlentities($row['asset_description']); - $asset_make = nullable_htmlentities($row['asset_make']); - $asset_model = nullable_htmlentities($row['asset_model']); - $asset_serial = nullable_htmlentities($row['asset_serial']); - $asset_os = nullable_htmlentities($row['asset_os']); - $asset_uri = sanitize_url($row['asset_uri']); - $asset_uri_2 = sanitize_url($row['asset_uri_2']); - $asset_uri_client = sanitize_url($row['asset_uri_client']); - $asset_status = nullable_htmlentities($row['asset_status']); - $asset_purchase_reference = nullable_htmlentities($row['asset_purchase_reference']); - $asset_purchase_date = nullable_htmlentities($row['asset_purchase_date']); - $asset_warranty_expire = nullable_htmlentities($row['asset_warranty_expire']); - $asset_install_date = nullable_htmlentities($row['asset_install_date']); - $asset_photo = nullable_htmlentities($row['asset_photo']); - $asset_physical_location = nullable_htmlentities($row['asset_physical_location']); - $asset_notes = nullable_htmlentities($row['asset_notes']); - $asset_created_at = nullable_htmlentities($row['asset_created_at']); - $asset_vendor_id = intval($row['asset_vendor_id']); - $asset_location_id = intval($row['asset_location_id']); - $asset_contact_id = intval($row['asset_contact_id']); + if (mysqli_num_rows($sql) == 0) { + echo " Nothing to see hereGo Back
+
-
+
-
-
-
-
-
-
-
- = $asset_name; ?>- -= $asset_description; ?>
-
-
-
-
- = $asset_type; ?>
-
- = "$asset_make $asset_model"; ?>
-
- = "$asset_os"; ?>
-
- = $asset_serial; ?>
-
- = date('Y-m-d', strtotime($asset_purchase_date)); ?>
-
- = date('Y-m-d', strtotime($asset_install_date)); ?>
-
- = date('Y-m-d', strtotime($asset_warranty_expire)); ?>
-
-
-
-
-
-
-
- Primary Network Interface-
-
-
- = $asset_ip; ?>
-
-
- = $asset_nat_ip; ?>
-
- = $asset_mac; ?>
-
-
-
-
-
-
- Client URI: = truncate($asset_uri_client, 40); ?>
-
-
-
-
-
-
- Assignment-
-
-
- = $location_name_display; ?>
-
- = $contact_name_display; ?>
-
-
-
- = formatPhoneNumber($contact_phone); echo " $contact_extension"; ?>
-
- = formatPhoneNumber($contact_mobile); ?>
-
-
-
-
-
-
-
-
- Additional Notes-
-
-
-
-
-
- New Ticket
-
-
-
- New Recurring Ticket
-
-
-
- New Credential
-
-
-
- New Document
-
-
-
- Upload file(s)
-
+
+
-
+
+ = $asset_name; ?>+ += $asset_description; ?>
+
+
+
+
= $asset_type; ?>
+
+ = "$asset_make $asset_model"; ?>
+
+ = "$asset_os"; ?>
+
+ = $asset_serial; ?>
+
+ = date('Y-m-d', strtotime($asset_purchase_date)); ?>
+
+ = date('Y-m-d', strtotime($asset_install_date)); ?>
+
+ = date('Y-m-d', strtotime($asset_warranty_expire)); ?>
+
-
-
- License
-
-
-
- Credential
-
-
-
- Service
-
-
-
- Document
-
-
-
- File
-
+
-
+
+
+
+
+
+ Primary Network Interface+
+
+
= $asset_ip; ?>
+
+
+ = $asset_nat_ip; ?>
+
+ = $asset_mac; ?>
+
+
+
+
+
+
+ Client URI: = truncate($asset_uri_client, 40); ?>
+
+
+
+
+
+ Assignment+
+
+
+ = $location_name_display; ?>
+
+ = $contact_name_display; ?>
+
+
+
+ = formatPhoneNumber($contact_phone); echo " $contact_extension"; ?>
+
+ = formatPhoneNumber($contact_mobile); ?>
+
+
+
+
+
+
+
+ Additional Notes+
-
- Interfaces-
-
-
-
-
+
+
+
+
+
+
+
+ New Ticket
+
+
+
+ New Recurring Ticket
+
+
+
+ New Credential
+
+
+
+ New Document
+
+
+
+ Upload file(s)
+
+
+
+
+
+
-
+
+ Interfaces+
+
+
+
+
+
+
+
+
-
@@ -716,24 +712,7 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
-
-
-
-
-
-
-
-
-
-
-
-
">
-
-
-
- Credentials-
-
-
-
">
+
+
+
+
+ Documents+
+
+
+
+
+
+
">
+
+
+
+
+
+
+
+
">
+
-
-
+
+ Recurring Tickets+
+
-
+
-
-
">
-
-
-
-
- Licenses-
-
-
-
-
-
-
">
-
-
-
+
-
- Documents-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- 0) {
- $os_arr = [];
- while ($row = mysqli_fetch_assoc($os_sql)) {
- // jQuery UI Autocomplete expects {label: "...", value: "..."}
- $label = $row['label'];
- $os_arr[] = ['label' => $label, 'value' => $label];
- }
- $json_os = json_encode($os_arr);
-}
-
?>
-
">
-
-
-
-
- Recurring Tickets-
-
-
-
-
">
-
+
-
- Tickets-
-
+
-
+
">
+
+ ?>
-
+
+ Linked Services+
+
+
+
-
+
-
">
-
+
-
- Linked Services-
-
-
-
-
@@ -185,8 +178,8 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
= 2) { ?>
-
@@ -310,27 +303,40 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
-
+
Assign Contact
-
+
Assign Location
-
+
Set Physical Location
-
+
Set Status
-
+
Create Tickets
-
+
Transfer to Client
@@ -699,16 +705,6 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) {
-
-
- Budget for-
-
- Edit Budget
-
-
-
-
-
-
diff --git a/agent/budget_edit.php b/agent/budget_edit.php
deleted file mode 100644
index 26af60ce..00000000
--- a/agent/budget_edit.php
+++ /dev/null
@@ -1,114 +0,0 @@
-
-
-
-
-
-
-
-
diff --git a/agent/calendar.php b/agent/calendar.php
index c8891783..e7924190 100644
--- a/agent/calendar.php
+++ b/agent/calendar.php
@@ -33,7 +33,7 @@ if (isset($_GET['calendar_id'])) {
-
- Editing Budget for- -
-
-
-
-
-
-
-
Calendars
-
@@ -82,8 +82,6 @@ if (isset($_GET['calendar_id'])) {
Certificates
-
@@ -249,8 +249,10 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
-
-
= 2) { ?>
|
-
-
+
+
+
+
|
@@ -303,11 +305,9 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
-
-
+
+ Open Tickets
+
+
+
Set Hourly Rate
-
+
Set Industry
-
+
Set Referral
-
+
Assign Tags
-
+
Send Email
@@ -178,49 +196,27 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
"
id="advancedFilter"
>
-
+
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+ Nothing to see hereGo Back"; + require_once "../includes/footer.php"; + exit(); + } + $row = mysqli_fetch_array($sql); $client_id = intval($row['client_id']); $client_name = nullable_htmlentities($row['client_name']); @@ -255,27 +262,27 @@ if (isset($_GET['contact_id'])) {
-
+
New Ticket
-
+
New Recurring Ticket
-
+
New Asset
-
+
New Credential
-
+
New Document
-
+
Upload file(s)
@@ -1172,12 +1179,4 @@ if (isset($_GET['contact_id'])) {
Contacts
-
-
+
Assign Location
-
+
Set Phone Number
-
+
Set Department
-
+
Set Roles
-
+
Assign Tags
-
+
Send Email
@@ -545,63 +558,18 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()"));
|
Expiring Domains
+Expiring Domains 30 Day
Expiring Certificates
+Expiring Certificates30 Day
|
-
-
-
- |
- - - Date - - | -- - Category - - / - - Description - - | -- - Vendor - - | -- - Amount - - | -- - Account - - | -- - Client - - | -Action | -
|---|
|
+
+
+
+ |
+ + + Date + + | ++ + Category + + / + + Description + + | ++ + Vendor + + | ++ + Amount + + | ++ + Account + + | ++ + Client + + | +Action | +
|---|---|---|---|---|---|---|---|
|
-
-
-
- |
- - - - - - | -- - - | -- | - | - | - |
-
-
- |
-
Asset ID: = $asset_id ?>
@@ -466,7 +467,7 @@ ob_start();Format csv file with headings & data:
Name, Description, Type, Make, Model, Serial, OS, Purchase Date, Assigned To, Location, Physical Location
Format csv file with headings & data:
Name, Description, Type, Make, Model, Serial, OS, Purchase Date, Assigned To, Location, Physical Location, Notes
Pin Top
Pin Top
-Receives Invoices
-Access
-Receives Invoices
+Access