= 2; // Deleting for good also needs Admin > Settings to allow destructive deletes $can_delete = lookupUserPermission('module_support') >= 3 && !empty($config_destructive_deletes_enable); $client = ''; if (!$client_url) { // Client Filter if (!empty($_GET['client'])) { $client = intval($_GET['client']); $client_query = "AND software_client_id = $client"; } } // Attention tabs - renewing, expired, over seats, nobody on it $status_filters = softwareStatusFilters(); $status = isset($status_filters[$_GET['status'] ?? '']) ? $_GET['status'] : ''; $_GET['status'] = $status; $status_query = $status ? "AND ({$status_filters[$status]['sql']})" : ''; // License type filter $license_type_filter = (string) ($_GET['license_type'] ?? ''); $license_type_query = $license_type_filter !== '' ? "AND software_license_type = '" . escapeSql($license_type_filter) . "'" : ''; // Expiring In Filter - the dashboard links here with expire_days=30 if (!empty($_GET['expire_days'])) { if ($_GET['expire_days'] == "expired") { $expire_days = "expired"; $expire_query = "AND (software_expire IS NOT NULL AND software_expire != '0000-00-00' AND software_expire < CURDATE())"; } else { $expire_days = intval($_GET['expire_days']); $expire_query = "AND (software_expire IS NOT NULL AND software_expire != '0000-00-00' AND software_expire BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL $expire_days DAY))"; } } else { // Default - any $expire_days = ''; $expire_query = ''; } // Extra columns, picked from the filter bar $extra_column_options = [ 'Key' => 'License key', 'Purchased' => 'Purchased', 'Order_Ref' => 'Order reference', ]; $extra_columns = array_values(array_intersect(array_keys($extra_column_options), (array) ($_GET['show_column'] ?? []))); $show_key = in_array('Key', $extra_columns, true); $show_purchased = in_array('Purchased', $extra_columns, true); $show_order_ref = in_array('Order_Ref', $extra_columns, true); // Only these sort - filter_header.php will hand through any lowercase word, and // an unknown column takes the page down with a mysqli exception $sortable_columns = [ 'software_name', 'software_type', 'software_license_type', 'seats_used', 'software_seats', 'software_expire', 'software_purchase', 'software_purchase_reference', 'vendor_name', 'client_name', 'software_created_at' ]; if (!in_array($sort, $sortable_columns, true)) { $sort = 'software_name'; } // No renewal date sorts last whichever way, so "soonest first" starts with a date $order_by = $sort === 'software_expire' ? "software_expire IS NULL, software_expire $order, software_name ASC" : "$sort $order, software_name ASC"; $seats_used_sql = softwareSeatsUsedSql('software.software_id'); // Tab counts - within the client and archive scope, before the search narrows it $count_columns = ["COUNT(*) AS all_count"]; foreach ($status_filters as $status_key => $status_filter) { $count_columns[] = "COALESCE(SUM({$status_filter['sql']}), 0) AS {$status_key}_count"; } $row = mysqli_fetch_assoc(mysqli_query($mysqli, " SELECT " . implode(', ', $count_columns) . " FROM software LEFT JOIN clients ON client_id = software_client_id WHERE $archive_query " . clientScopeSql('software_client_id') . " $client_query ")); $tab_counts = ['' => intval($row['all_count'])]; foreach (array_keys($status_filters) as $status_key) { $tab_counts[$status_key] = intval($row["{$status_key}_count"]); } $sql = mysqli_query( $mysqli, "SELECT SQL_CALC_FOUND_ROWS client_id, client_name, software_created_at, software_description, software_expire, software_id, software_license_type, software_name, software_seats, software_type, software_key, software_favorite, software_purchase, software_purchase_reference, software_version, software_archived_at, vendor_id, vendor_name, $seats_used_sql AS seats_used, (SELECT COUNT(*) FROM software_keys WHERE software_key_software_id = software.software_id) AS key_count FROM software LEFT JOIN clients ON client_id = software_client_id LEFT JOIN vendors ON vendor_id = software_vendor_id WHERE (software_name LIKE '%$q%' OR software_description LIKE '%$q%' OR software_type LIKE '%$q%' OR software_license_type LIKE '%$q%' OR software_key LIKE '%$q%' OR software_purchase_reference LIKE '%$q%' OR vendor_name LIKE '%$q%' OR client_name LIKE '%$q%' OR software.software_id IN (SELECT software_key_software_id FROM software_keys WHERE software_key LIKE '%$q%')) AND $archive_query " . clientScopeSql('software_client_id') . " $client_query $status_query $license_type_query $expire_query ORDER BY $order_by LIMIT $record_from, $record_to"); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); // License types in use here, for the filter $license_type_options = []; $sql_license_types = mysqli_query($mysqli, "SELECT DISTINCT software_license_type FROM software LEFT JOIN clients ON client_id = software_client_id WHERE software_license_type IS NOT NULL AND software_license_type != '' AND $archive_query " . clientScopeSql('software_client_id') . " $client_query ORDER BY software_license_type ASC"); while ($license_type_row = mysqli_fetch_row($sql_license_types)) { $license_type_options[] = $license_type_row[0]; } ?>

Licenses

Archived
'licenses', 'icon' => 'fa-cube', 'views' => ['status'], 'view' => emptyStatePill($status_filters, $status, '', ['renewing', 'expired', 'over', 'unused']), 'text' => 'Their software and subscriptions - the seats bought, who and what uses them, and when each renews.', 'actions' => $can_edit ? [['label' => 'New License', 'modal' => "modals/software/software_add.php?$client_url", 'size' => 'lg']] : [], ]; require_once "../includes/filter_footer.php"; ?>