From 6cdc26b55bc7ef867d4aaf13f0b825521636bf7d Mon Sep 17 00:00:00 2001 From: johnnyq Date: Sun, 9 Nov 2025 12:24:04 -0500 Subject: [PATCH 01/32] Fix broken edit payment methods due to missing hidden field --- admin/modals/payment_method/payment_method_edit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/modals/payment_method/payment_method_edit.php b/admin/modals/payment_method/payment_method_edit.php index d6c70386..c063640a 100644 --- a/admin/modals/payment_method/payment_method_edit.php +++ b/admin/modals/payment_method/payment_method_edit.php @@ -22,7 +22,7 @@ ob_start();
- +
@@ -86,7 +89,7 @@ ob_start(); diff --git a/admin/modals/tag/tag_edit.php b/admin/modals/tag/tag_edit.php index 8aa3c2ae..bfd49962 100644 --- a/admin/modals/tag/tag_edit.php +++ b/admin/modals/tag/tag_edit.php @@ -47,6 +47,7 @@ ob_start(); + @@ -73,7 +74,7 @@ ob_start(); diff --git a/admin/post/contract_template.php b/admin/post/contract_template.php index 585e3c9e..6e277a3e 100644 --- a/admin/post/contract_template.php +++ b/admin/post/contract_template.php @@ -9,11 +9,12 @@ defined('FROM_POST_HANDLER') || die("Direct file access is not allowed"); if (isset($_POST['add_contract_template'])) { // Sanitize text inputs - $name = sanitizeInput($_POST['contract_template_name']); - $type = sanitizeInput($_POST['contract_template_type']); - $update_frequency = sanitizeInput($_POST['contract_template_update_frequency']); - $support_hours = sanitizeInput($_POST['contract_template_support_hours']); - $details = mysql_escape_string($mysqli, $_POST['contract_template_details']); + $name = sanitizeInput($_POST['name']); + $description = sanitizeInput($_POST['description']); + $type = sanitizeInput($_POST['type']); + $renewal_frequency = sanitizeInput($_POST['renewal_frequency']); + $support_hours = sanitizeInput($_POST['support_hours']); + $details = mysqli_escape_string($mysqli, $_POST['details']); // Numeric fields cast to integer $sla_low_resp = intval($_POST['sla_low_response_time']); @@ -22,9 +23,9 @@ if (isset($_POST['add_contract_template'])) { $sla_low_res = intval($_POST['sla_low_resolution_time']); $sla_med_res = intval($_POST['sla_medium_resolution_time']); $sla_high_res = intval($_POST['sla_high_resolution_time']); - $hourly_rate = intval($_POST['contract_template_hourly_rate']); - $after_hours_rate = intval($_POST['contract_template_after_hours_hourly_rate']); - $net_terms = intval($_POST['contract_template_net_terms']); + $rate_standard = intval($_POST['rate_standard']); + $rate_after_hours = intval($_POST['hourly_rate_after_hours']); + $net_terms = intval($_POST['net_terms']); // Insert into database (numbers not quoted) mysqli_query($mysqli, " @@ -33,19 +34,17 @@ if (isset($_POST['add_contract_template'])) { contract_template_description = '$description', contract_template_details = '$details', contract_template_type = '$type', - contract_template_update_frequency = '$update_frequency', - sla_low_response_time = $sla_low_resp, - sla_medium_response_time = $sla_med_resp, - sla_high_response_time = $sla_high_resp, - sla_low_resolution_time = $sla_low_res, - sla_medium_resolution_time = $sla_med_res, - sla_high_resolution_time = $sla_high_res, - contract_template_hourly_rate = $hourly_rate, - contract_template_after_hours_hourly_rate = $after_hours_rate, + contract_template_renewal_frequency = '$renewal_frequency', + contract_template_sla_low_response_time = $sla_low_resp, + contract_template_sla_medium_response_time = $sla_med_resp, + contract_template_sla_high_response_time = $sla_high_resp, + contract_template_sla_low_resolution_time = $sla_low_res, + contract_template_sla_medium_resolution_time = $sla_med_res, + contract_template_sla_high_resolution_time = $sla_high_res, + contract_template_rate_standard = $rate_standard, + contract_template_rate_after_hours = $rate_after_hours, contract_template_support_hours = '$support_hours', - contract_template_net_terms = $net_terms, - contract_template_created_by = $session_user_id, - contract_template_created_at = NOW() + contract_template_net_terms = $net_terms "); $contract_template_id = mysqli_insert_id($mysqli); @@ -60,4 +59,99 @@ if (isset($_POST['add_contract_template'])) { redirect(); } +if (isset($_POST['edit_contract_template'])) { + + $contract_template_id = intval($_POST['contract_template_id']); + $name = sanitizeInput($_POST['name']); + $description = sanitizeInput($_POST['description']); + $type = sanitizeInput($_POST['type']); + $renewal_frequency= sanitizeInput($_POST['renewal_frequency']); + $support_hours = sanitizeInput($_POST['support_hours']); + $details = mysqli_escape_string($mysqli, $_POST['details']); + $sla_low_resp = intval($_POST['sla_low_response_time']); + $sla_med_resp = intval($_POST['sla_medium_response_time']); + $sla_high_resp = intval($_POST['sla_high_response_time']); + $sla_low_res = intval($_POST['sla_low_resolution_time']); + $sla_med_res = intval($_POST['sla_medium_resolution_time']); + $sla_high_res = intval($_POST['sla_high_resolution_time']); + $rate_standard = intval($_POST['rate_standard']); + $rate_after_hours = intval($_POST['rate_after_hours']); + $net_terms = intval($_POST['net_terms']); + + mysqli_query($mysqli, " + UPDATE contract_templates SET + contract_template_name = '$name', + contract_template_description = '$description', + contract_template_details = '$details', + contract_template_type = '$type', + contract_template_renewal_frequency = '$renewal_frequency', + contract_template_sla_low_response_time = $sla_low_resp, + contract_template_sla_medium_response_time = $sla_med_resp, + contract_template_sla_high_response_time = $sla_high_resp, + contract_template_sla_low_resolution_time = $sla_low_res, + contract_template_sla_medium_resolution_time = $sla_med_res, + contract_template_sla_high_resolution_time = $sla_high_res, + contract_template_rate_standard = $rate_standard, + contract_template_rate_after_hours = $rate_after_hours, + contract_template_support_hours = '$support_hours', + contract_template_net_terms = $net_terms + WHERE contract_template_id = $contract_template_id + "); + + // Log action + logAction("Contract Template", "Update", "$session_name updated contract template $name", 0, $contract_template_id); + + // Flash + redirect + flash_alert("Contract Template $name updated"); + redirect(); +} + +if (isset($_GET['archive_contract_template'])) { + $contract_template_id = intval($_GET['archive_contract_template']); + + $name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name'); + + mysqli_query($mysqli, " + UPDATE contract_templates SET contract_template_archived_at = NOW() + WHERE contract_template_id = $contract_template_id + LIMIT 1 + "); + + logAction("Contract Template", "Archive", "$session_name archived contract template $name", 0, $contract_template_id); + flash_alert("Contract Template $name archived", "danger"); + redirect(); +} + +if (isset($_GET['restore_contract_template'])) { + $contract_template_id = intval($_GET['restore_contract_template']); + + $name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name'); + + mysqli_query($mysqli, " + UPDATE contract_templates SET contract_template_archived_at = NULL + WHERE contract_template_id = $contract_template_id + LIMIT 1 + "); + + logAction("Contract Template", "Restore", "$session_name restored contract template $name", 0, $contract_template_id); + flash_alert("Contract Template $name restored"); + redirect(); +} + +if (isset($_GET['delete_contract_template'])) { + $contract_template_id = intval($_GET['delete_contract_template']); + + $name = getFieldById('contract_templates', $contract_template_id, 'contract_template_name'); + + mysqli_query($mysqli, " + DELETE FROM contract_templates + WHERE contract_template_id = $contract_template_id + LIMIT 1 + "); + + logAction("Contract Template", "Delete", "$session_name deleted contract template $name", 0, $contract_template_id); + flash_alert("Contract Template $name deleted", "danger"); + redirect(); +} + ?> diff --git a/admin/tag.php b/admin/tag.php index 33c7d5e9..fe2171fd 100644 --- a/admin/tag.php +++ b/admin/tag.php @@ -74,6 +74,8 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $tag_type_display = "Contact Tag"; } elseif ( $tag_type == 4) { $tag_type_display = "Credential Tag"; + } elseif ( $tag_type == 5) { + $tag_type_display = "Asset Tag"; } else { $tag_type_display = "Unknown Tag"; } diff --git a/agent/assets.php b/agent/assets.php index c03d4eb4..04c33732 100644 --- a/agent/assets.php +++ b/agent/assets.php @@ -78,6 +78,18 @@ if ($client_url && isset($_GET['location']) && !empty($_GET['location'])) { $location_filter = 0; } +// Tags Filter +if (isset($_GET['tags']) && is_array($_GET['tags']) && !empty($_GET['tags'])) { + // Sanitize each element of the tags array + $sanitizedTags = array_map('intval', $_GET['tags']); + // Convert the sanitized tags into a comma-separated string + $tag_filter = implode(",", $sanitizedTags); + $tag_query = "AND tag_id IN ($tag_filter)"; +} else { + $tag_filter = 0; + $tag_query = ''; +} + //Get Asset Counts $row = mysqli_fetch_assoc(mysqli_query($mysqli, " SELECT @@ -93,9 +105,13 @@ $row = mysqli_fetch_assoc(mysqli_query($mysqli, " LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN locations ON asset_location_id = location_id LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 + LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id + LEFT JOIN tags ON tag_id = asset_tag_tag_id WHERE $archive_query + $tag_query $access_permission_query $client_query + GROUP BY asset_id ) AS filtered_assets; ")); @@ -127,13 +143,16 @@ $sql = mysqli_query( LEFT JOIN contacts ON asset_contact_id = contact_id LEFT JOIN locations ON asset_location_id = location_id LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 + LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id + LEFT JOIN tags ON tag_id = asset_tag_tag_id WHERE $archive_query - AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%') + $tag_query + AND (asset_name LIKE '%$q%' OR asset_description LIKE '%$q%' OR asset_type LIKE '%$q%' OR interface_ip LIKE '%$q%' OR interface_ipv6 LIKE '%$q%' OR interface_mac LIKE '%$q%' OR asset_make LIKE '%$q%' OR asset_model LIKE '%$q%' OR asset_serial LIKE '%$q%' OR asset_os LIKE '%$q%' OR contact_name LIKE '%$q%' OR location_name LIKE '%$q%' OR client_name LIKE '%$q%' OR tag_name LIKE '%$q%') AND ($type_query) $access_permission_query $location_query $client_query - + GROUP BY asset_id ORDER BY $sort $order LIMIT $record_from, $record_to" ); @@ -270,7 +289,32 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); -
+
+
+ +
+
+
+
- +
- +
-
-
+
+
+ +
+ +
+
diff --git a/agent/modals/asset/asset_add.php b/agent/modals/asset/asset_add.php index 0b6ebccf..cda60a46 100644 --- a/agent/modals/asset/asset_add.php +++ b/agent/modals/asset/asset_add.php @@ -27,6 +27,8 @@ if ($os_sql && mysqli_num_rows($os_sql) > 0) { $json_os = json_encode($os_arr); } +$sql_tags_select = mysqli_query($mysqli, "SELECT tag_id, tag_name FROM tags WHERE tag_type = 5 ORDER BY tag_name ASC"); + ob_start(); ?> @@ -465,6 +467,33 @@ ob_start();
+
+ +
+
+ +
+ +
+ +
+
+
+ +
diff --git a/agent/modals/asset/asset_bulk_assign_tags.php b/agent/modals/asset/asset_bulk_assign_tags.php new file mode 100644 index 00000000..e5bd8341 --- /dev/null +++ b/agent/modals/asset/asset_bulk_assign_tags.php @@ -0,0 +1,61 @@ + + + +
+ + + + + + +
+ + @@ -462,6 +469,33 @@ ob_start(); +
+ +
+
+ +
+ +
+ +
+
+
+

Asset ID:

diff --git a/agent/post/asset.php b/agent/post/asset.php index b22c8de5..8c1d22a6 100644 --- a/agent/post/asset.php +++ b/agent/post/asset.php @@ -20,6 +20,14 @@ if (isset($_POST['add_asset'])) { $asset_id = mysqli_insert_id($mysqli); + // Add Tags + if (isset($_POST['tags'])) { + foreach($_POST['tags'] as $tag) { + $tag = intval($tag); + mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag"); + } + } + // Add Photo if (isset($_FILES['file']['tmp_name'])) { if ($new_file_name = checkFileUpload($_FILES['file'], array('jpg', 'jpeg', 'gif', 'png', 'webp'))) { @@ -108,6 +116,18 @@ if (isset($_POST['edit_asset'])) { mysqli_query($mysqli,"UPDATE assets SET asset_photo = '$new_file_name' WHERE asset_id = $asset_id"); } + // Tags + // Delete existing tags + mysqli_query($mysqli, "DELETE FROM asset_tags WHERE asset_tag_asset_id = $asset_id"); + + // Add new tags + if (isset($_POST['tags'])) { + foreach($_POST['tags'] as $tag) { + $tag = intval($tag); + mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag"); + } + } + logAction("Asset", "Edit", "$session_name edited asset $name", $client_id, $asset_id); flash_alert("Asset $name edited"); @@ -188,6 +208,50 @@ if (isset($_GET['delete_asset'])) { } +if (isset($_POST['bulk_assign_asset_tags'])) { + + enforceUserPermission('module_client', 2); + + if (isset($_POST['asset_ids'])) { + + $count = count($_POST['asset_ids']); + + foreach($_POST['asset_ids'] as $asset_id) { + $asset_id = intval($asset_id); + + $sql = mysqli_query($mysqli,"SELECT asset_name, asset_client_id FROM assets WHERE asset_id = $asset_id"); + $row = mysqli_fetch_array($sql); + $asset_name = sanitizeInput($row['asset_name']); + $client_id = intval($row['asset_client_id']); + + if($_POST['remove_tags']) { + mysqli_query($mysqli, "DELETE FROM asset_tags WHERE asset_tag_asset_id = $asset_id"); + } + + if (isset($_POST['tags'])) { + foreach($_POST['tags'] as $tag) { + $tag = intval($tag); + + $sql = mysqli_query($mysqli,"SELECT * FROM asset_tags WHERE asset_tag_asset_id = $asset_id AND asset_tag_tag_id = $tag"); + if (mysqli_num_rows($sql) == 0) { + mysqli_query($mysqli, "INSERT INTO asset_tags SET asset_tag_asset_id = $asset_id, asset_tag_tag_id = $tag"); + } + } + } + + logAction("Asset", "Edit", "$session_name added tags to asset $asset_name", $client_id, $asset_id); + + } + + logAction("Asset", "Bulk Edit", "$session_name added tags for $asset_count assets", $client_id); + + flash_alert("Assigned tags for $count assets"); + } + + redirect(); + +} + if (isset($_POST['bulk_assign_asset_location'])) { validateCSRFToken($_POST['csrf_token']); diff --git a/db.sql b/db.sql index 6a1fddf5..42af2911 100644 --- a/db.sql +++ b/db.sql @@ -275,6 +275,23 @@ CREATE TABLE `asset_notes` ( ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; +-- +-- Table structure for table `asset_tags` +-- + +DROP TABLE IF EXISTS `asset_tags`; +/*!40101 SET @saved_cs_client = @@character_set_client */; +/*!40101 SET character_set_client = utf8mb4 */; +CREATE TABLE `asset_tags` ( + `asset_tag_asset_id` int(11) NOT NULL, + `asset_tag_tag_id` int(11) NOT NULL, + PRIMARY KEY (`asset_tag_asset_id`,`asset_tag_tag_id`), + KEY `fk_tag` (`asset_tag_tag_id`), + CONSTRAINT `fk_asset` FOREIGN KEY (`asset_tag_asset_id`) REFERENCES `assets` (`asset_id`) ON DELETE CASCADE, + CONSTRAINT `fk_tag` FOREIGN KEY (`asset_tag_tag_id`) REFERENCES `tags` (`tag_id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; +/*!40101 SET character_set_client = @saved_cs_client */; + -- -- Table structure for table `assets` -- @@ -800,7 +817,6 @@ CREATE TABLE `contract_templates` ( `contract_template_created_at` datetime DEFAULT current_timestamp(), `contract_template_updated_at` datetime DEFAULT NULL ON UPDATE current_timestamp(), `contract_template_archived_at` datetime DEFAULT NULL, - `company_id` int(11) NOT NULL, PRIMARY KEY (`contract_template_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; @@ -2897,4 +2913,4 @@ CREATE TABLE `vendors` ( /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; --- Dump completed on 2025-11-07 16:47:40 +-- Dump completed on 2025-11-11 19:57:21 diff --git a/includes/database_version.php b/includes/database_version.php index 550ddbd1..63110ccf 100644 --- a/includes/database_version.php +++ b/includes/database_version.php @@ -5,4 +5,4 @@ * It is used in conjunction with database_updates.php */ -DEFINE("LATEST_DATABASE_VERSION", "2.3.7"); +DEFINE("LATEST_DATABASE_VERSION", "2.3.8"); From 0ac76766bd59c6433a98bf1f5ec503968d98d5ed Mon Sep 17 00:00:00 2001 From: johnnyq Date: Tue, 11 Nov 2025 21:05:59 -0500 Subject: [PATCH 03/32] Add Asset Tags Display in Contact Details, asset details, along with their detail modals --- agent/asset_details.php | 29 +++++++++++++++++- agent/assets.php | 1 + agent/contact_details.php | 39 ++++++++++++++++++++++-- agent/modals/asset/asset_details.php | 29 +++++++++++++++++- agent/modals/contact/contact_details.php | 38 +++++++++++++++++++++-- 5 files changed, 130 insertions(+), 6 deletions(-) diff --git a/agent/asset_details.php b/agent/asset_details.php index 8a5848ca..bdbc3452 100644 --- a/agent/asset_details.php +++ b/agent/asset_details.php @@ -118,6 +118,28 @@ if (isset($_GET['asset_id'])) { ); $document_count = mysqli_num_rows($sql_related_documents); + // Tags - many to many relationship + $asset_tag_name_display_array = array(); + $asset_tag_id_array = array(); + $sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC"); + while ($row = mysqli_fetch_array($sql_asset_tags)) { + + $asset_tag_id = intval($row['tag_id']); + $asset_tag_name = nullable_htmlentities($row['tag_name']); + $asset_tag_color = nullable_htmlentities($row['tag_color']); + if (empty($asset_tag_color)) { + $asset_tag_color = "dark"; + } + $asset_tag_icon = nullable_htmlentities($row['tag_icon']); + if (empty($asset_tag_icon)) { + $asset_tag_icon = "tag"; + } + + $asset_tag_id_array[] = $asset_tag_id; + $asset_tag_name_display_array[] = "$asset_tag_name"; + } + $asset_tags_display = implode('', $asset_tag_name_display_array); + // Network Interfaces $sql_related_interfaces = mysqli_query($mysqli, " SELECT @@ -257,8 +279,13 @@ if (isset($_GET['asset_id'])) {
+ +
+ +
+ -
+
diff --git a/agent/assets.php b/agent/assets.php index 04c33732..237ed926 100644 --- a/agent/assets.php +++ b/agent/assets.php @@ -358,6 +358,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); data-bulk="true"> Assign Location + @@ -413,6 +442,12 @@ if (isset($_GET['contact_id'])) {
+ +
+ +
+ diff --git a/agent/modals/asset/asset_details.php b/agent/modals/asset/asset_details.php index 85f59640..f7e771e2 100644 --- a/agent/modals/asset/asset_details.php +++ b/agent/modals/asset/asset_details.php @@ -70,6 +70,28 @@ if ($location_archived_at) { $location_name_display = $location_name; } +// Tags - many to many relationship +$asset_tag_name_display_array = array(); +$asset_tag_id_array = array(); +$sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC"); +while ($row = mysqli_fetch_array($sql_asset_tags)) { + + $asset_tag_id = intval($row['tag_id']); + $asset_tag_name = nullable_htmlentities($row['tag_name']); + $asset_tag_color = nullable_htmlentities($row['tag_color']); + if (empty($asset_tag_color)) { + $asset_tag_color = "dark"; + } + $asset_tag_icon = nullable_htmlentities($row['tag_icon']); + if (empty($asset_tag_icon)) { + $asset_tag_icon = "tag"; + } + + $asset_tag_id_array[] = $asset_tag_id; + $asset_tag_name_display_array[] = "
$asset_tag_name"; +} +$asset_tags_display = implode('', $asset_tag_name_display_array); + // Network Interfaces $sql_related_interfaces = mysqli_query($mysqli, " SELECT @@ -262,8 +284,13 @@ ob_start();
+ +
+ +
+ -
+
diff --git a/agent/modals/contact/contact_details.php b/agent/modals/contact/contact_details.php index 59e4ff11..a6121544 100644 --- a/agent/modals/contact/contact_details.php +++ b/agent/modals/contact/contact_details.php @@ -51,7 +51,14 @@ $auth_method = nullable_htmlentities($row['user_auth_method']); $contact_client_id = intval($row['contact_client_id']); // Related Assets Query - 1 to 1 relationship -$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 WHERE asset_contact_id = $contact_id ORDER BY asset_name DESC"); +$sql_related_assets = mysqli_query($mysqli, "SELECT * FROM assets + LEFT JOIN asset_interfaces ON interface_asset_id = asset_id AND interface_primary = 1 + LEFT JOIN asset_tags ON asset_tag_asset_id = asset_id + LEFT JOIN tags ON tag_id = asset_tag_tag_id + WHERE asset_contact_id = $contact_id + GROUP BY asset_id + ORDER BY asset_name ASC" +); $asset_count = mysqli_num_rows($sql_related_assets); // Linked Software Licenses @@ -77,7 +84,7 @@ $sql_related_credentials = mysqli_query($mysqli, " LEFT JOIN tags ON tags.tag_id = credential_tags.tag_id WHERE credential_contact_id = $contact_id GROUP BY credentials.credential_id - ORDER BY credential_name DESC + ORDER BY credential_name ASC "); $credential_count = mysqli_num_rows($sql_related_credentials); @@ -376,6 +383,27 @@ ob_start(); $asset_notes = nullable_htmlentities($row['asset_notes']); $asset_created_at = nullable_htmlentities($row['asset_created_at']); $device_icon = getAssetIcon($asset_type); + // Tags + $asset_tag_name_display_array = array(); + $asset_tag_id_array = array(); + $sql_asset_tags = mysqli_query($mysqli, "SELECT * FROM asset_tags LEFT JOIN tags ON asset_tag_tag_id = tag_id WHERE asset_tag_asset_id = $asset_id ORDER BY tag_name ASC"); + while ($row = mysqli_fetch_array($sql_asset_tags)) { + + $asset_tag_id = intval($row['tag_id']); + $asset_tag_name = nullable_htmlentities($row['tag_name']); + $asset_tag_color = nullable_htmlentities($row['tag_color']); + if (empty($asset_tag_color)) { + $asset_tag_color = "dark"; + } + $asset_tag_icon = nullable_htmlentities($row['tag_icon']); + if (empty($asset_tag_icon)) { + $asset_tag_icon = "tag"; + } + + $asset_tag_id_array[] = $asset_tag_id; + $asset_tag_name_display_array[] = "$asset_tag_name"; + } + $asset_tags_display = implode('', $asset_tag_name_display_array); ?> @@ -389,6 +417,12 @@ ob_start();
+ +
+ +
+ From 15ed4ef1ce058fb70b6b566de17aadf816d7a454 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 12 Nov 2025 14:35:06 -0500 Subject: [PATCH 04/32] Fix unable to delete Vendor Templates --- admin/vendor_template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/vendor_template.php b/admin/vendor_template.php index 716371b9..b201d0df 100644 --- a/admin/vendor_template.php +++ b/admin/vendor_template.php @@ -140,7 +140,7 @@ $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); - + Delete From 26ab43c57ffab6c5e8b52137b07b81dec16f1a93 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 12 Nov 2025 14:50:05 -0500 Subject: [PATCH 05/32] Fix Mail Queue link when sending a test email, updated the quote send email wording to Quote sent --- admin/post/settings_mail.php | 2 +- agent/post/quote.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/post/settings_mail.php b/admin/post/settings_mail.php index d7b2e6a7..e515e75d 100644 --- a/admin/post/settings_mail.php +++ b/admin/post/settings_mail.php @@ -150,7 +150,7 @@ if (isset($_POST['test_email_smtp'])) { $mail = addToMailQueue($data); if ($mail === true) { - flash_alert("Test email queued! Check Admin > Mail queue"); + flash_alert("Test email queued! Check Admin > Mail queue"); } else { flash_alert("Failed to add test mail to queue", 'error'); } diff --git a/agent/post/quote.php b/agent/post/quote.php index 0b9e2a4c..6a8695a0 100644 --- a/agent/post/quote.php +++ b/agent/post/quote.php @@ -497,7 +497,7 @@ if (isset($_GET['email_quote'])) { logAction("Quote", "Email", "$session_name emailed quote $quote_prefix$quote_number to $contact_email", $client_id, $quote_id); - flash_alert("Quote has been queued successfully! See Mail Queue"); + flash_alert("Quote sent!"); //Don't change the status to sent if the status is anything but draft if ($quote_status == 'Draft') { From af8e733cfb1394861a04e74225dced5bca1089cd Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 12 Nov 2025 16:27:03 -0500 Subject: [PATCH 06/32] Added Quick Add Links to the majority of Side bars navs --- admin/includes/side_nav.php | 80 ++++++++++++++++----- agent/includes/client_overview_side_nav.php | 9 +++ agent/includes/client_side_nav.php | 22 +++++- agent/includes/side_nav.php | 23 ++++-- 4 files changed, 112 insertions(+), 22 deletions(-) diff --git a/admin/includes/side_nav.php b/admin/includes/side_nav.php index 3cbe9ccc..dabf89d8 100644 --- a/admin/includes/side_nav.php +++ b/admin/includes/side_nav.php @@ -18,25 +18,37 @@ @@ -44,26 +56,38 @@ @@ -113,37 +143,55 @@ diff --git a/agent/includes/client_overview_side_nav.php b/agent/includes/client_overview_side_nav.php index bdd81b8f..429ac5de 100644 --- a/agent/includes/client_overview_side_nav.php +++ b/agent/includes/client_overview_side_nav.php @@ -53,6 +53,7 @@ $num_software = $row['num'];

Contacts + 0) { ?> @@ -65,6 +66,7 @@ $num_software = $row['num'];

Locations + 0) { ?> @@ -77,6 +79,7 @@ $num_software = $row['num'];

Assets + 0) { ?> @@ -89,6 +92,7 @@ $num_software = $row['num'];

Licenses + 0) { ?> @@ -101,6 +105,7 @@ $num_software = $row['num'];

Credentials + 0) { ?> @@ -113,6 +118,7 @@ $num_software = $row['num'];

Networks + 0) { ?> @@ -125,6 +131,7 @@ $num_software = $row['num'];

Certificates + 0) { ?> @@ -137,6 +144,7 @@ $num_software = $row['num'];

Domains + 0) { ?> @@ -149,6 +157,7 @@ $num_software = $row['num'];

Services + 0) { ?> diff --git a/agent/includes/client_side_nav.php b/agent/includes/client_side_nav.php index 1090ebe3..d7c479d5 100644 --- a/agent/includes/client_side_nav.php +++ b/agent/includes/client_side_nav.php @@ -30,6 +30,7 @@

Contacts + 0) { ?> @@ -43,6 +44,7 @@

Locations + 0) { ?> @@ -59,6 +61,7 @@

Tickets + 0) { ?> @@ -73,6 +76,7 @@

Recurring Tickets + @@ -87,6 +91,7 @@

Projects + @@ -101,6 +106,7 @@

Vendors + 0) { ?> @@ -132,6 +138,7 @@

Assets + 0) { ?> @@ -145,6 +152,7 @@

Licenses + 0) { ?> @@ -159,6 +167,7 @@

Credentials + 0) { ?> @@ -173,6 +182,7 @@

Networks + 0) { ?> @@ -186,6 +196,7 @@

Racks + 0) { ?> @@ -199,7 +210,7 @@

Certificates - + 0) { ?> @@ -213,7 +224,7 @@

Domains - + 0) { ?> @@ -227,6 +238,7 @@

Services + 0) { ?> @@ -240,6 +252,7 @@

Documents + 0) { ?> @@ -256,6 +269,7 @@

Files + 0) { ?> @@ -277,6 +291,7 @@

Invoices + 0) { ?> @@ -290,6 +305,7 @@

Recurring Invoices + @@ -303,6 +319,7 @@

Quotes + 0) { ?> @@ -333,6 +350,7 @@

Trips + 0) { ?> diff --git a/agent/includes/side_nav.php b/agent/includes/side_nav.php index dcc56be7..10f97da8 100644 --- a/agent/includes/side_nav.php +++ b/agent/includes/side_nav.php @@ -23,10 +23,11 @@ ">

- Clients - - - + Clients + + + +

@@ -40,6 +41,7 @@

Tickets + @@ -51,6 +53,7 @@

Recurring Tickets + @@ -62,6 +65,7 @@

Projects + @@ -84,6 +88,7 @@

Quotes + @@ -95,6 +100,7 @@

Invoices + @@ -106,6 +112,7 @@

Recurring Invoices + @@ -116,12 +123,14 @@ ">

Revenues

+ @@ -137,12 +146,14 @@ ">

Vendors

+
From 7230325e62ca9b27667c7c5a142c7ebf6ea5e4a7 Mon Sep 17 00:00:00 2001 From: johnnyq Date: Wed, 12 Nov 2025 17:04:53 -0500 Subject: [PATCH 07/32] Migrate Ticket Template add to ajax-modal, add category type option if not defined, add product type if not defined --- admin/includes/side_nav.php | 2 +- admin/modals/category/category_add.php | 28 +++- .../ticket_template/ticket_template_add.php | 142 +++++++++--------- admin/ticket_template.php | 3 +- agent/modals/product/product_add.php | 25 ++- 5 files changed, 124 insertions(+), 76 deletions(-) diff --git a/admin/includes/side_nav.php b/admin/includes/side_nav.php index dabf89d8..e2fedd98 100644 --- a/admin/includes/side_nav.php +++ b/admin/includes/side_nav.php @@ -162,7 +162,7 @@

- + Ticket Templates

diff --git a/admin/modals/category/category_add.php b/admin/modals/category/category_add.php index 52d9769d..8fa6ac74 100644 --- a/admin/modals/category/category_add.php +++ b/admin/modals/category/category_add.php @@ -2,7 +2,9 @@ require_once '../../../includes/modal_header.php'; -$category = nullable_htmlentities($_GET['category']); +$category = nullable_htmlentities($_GET['category'] ?? ''); + +$category_types_array = ['Expense', 'Income', 'Referral', 'Ticket']; ?> @@ -13,10 +15,30 @@ $category = nullable_htmlentities($_GET['category']);
-