= 2; $can_delete = lookupUserPermission('module_sales') >= 3; // Client Filter (all clients) $client = ''; if (!$client_url && !empty($_GET['client'])) { $client = intval($_GET['client']); $client_query = "AND contract_client_id = $client AND " . contractClientLiveSql(); } $type_filter = isset(CONTRACT_TYPES[$_GET['type'] ?? '']) ? $_GET['type'] : ''; $type_query = $type_filter !== '' ? "AND contract_type = '" . escapeSql($type_filter) . "'" : ''; $views = contractViews(); $view = isset($views[$_GET['show'] ?? '']) ? $_GET['show'] : 'active'; $sortable_columns = [ 'contract_name' => "contract_name $order", 'client_name' => "client_name $order, contract_name ASC", 'contract_type' => "contract_type $order, contract_name ASC", 'contract_start_date' => "contract_start_date IS NULL, contract_start_date $order", 'contract_end_date' => "contract_end_date IS NULL, contract_end_date $order", 'owner_name' => "user_name IS NULL, user_name $order", ]; if (!isset($sortable_columns[$sort])) { $sort = 'contract_end_date'; } $scope_query = clientScopeSql('contract_client_id'); $search_query = "AND (contract_name LIKE '%$q%' OR client_name LIKE '%$q%' OR contract_support_hours LIKE '%$q%' OR contract_notes LIKE '%$q%')"; $joins = "LEFT JOIN clients ON contract_client_id = client_id LEFT JOIN users ON contract_owner_id = user_id"; $filters = "AND contract_archived_at IS NULL $scope_query $client_query $type_query $search_query"; $contracts = []; $num_rows = [0]; $counts = array_fill_keys(array_keys($views), 0); $stats = ['active' => 0, 'ending' => 0, 'renewing' => 0, 'draft' => 0]; if (contractsReady()) { $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS contracts.*, client_name, client_archived_at, user_name AS owner_name FROM contracts $joins WHERE {$views[$view]['where']} $filters ORDER BY {$sortable_columns[$sort]}, contract_id ASC LIMIT $record_from, $record_to"); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); while ($row = mysqli_fetch_assoc($sql)) { $contracts[] = $row; } // Where each one's latest signing request stands $signing = []; if ($contracts && contractSignaturesReady()) { $ids = implode(',', array_map(function ($row) { return intval($row['contract_id']); }, $contracts)); $sql = mysqli_query($mysqli, "SELECT contract_signature_id, contract_signature_contract_id, contract_signature_url_key, contract_signature_sent_at, contract_signature_viewed_at, contract_signature_client_name, contract_signature_client_signed_at, contract_signature_agent_signed_at, contract_signature_withdrawn_at FROM contract_signatures WHERE contract_signature_id IN (SELECT MAX(contract_signature_id) FROM contract_signatures WHERE contract_signature_contract_id IN ($ids) GROUP BY contract_signature_contract_id)"); $by_id = array_column($contracts, null, 'contract_id'); while ($round = mysqli_fetch_assoc($sql)) { $id = intval($round['contract_signature_contract_id']); $signing[$id] = contractSignatureState($round + array_intersect_key($by_id[$id] ?? [], ['contract_status' => 1, 'client_archived_at' => 1])); } } // The ones that can't be deleted, and why $delete_blocked = $can_delete ? contractDeleteBlockers($contracts) : []; // Prepaid hours left on each $hours_left = contractHoursLeftFor(array_column($contracts, 'contract_id')); $row = mysqli_fetch_row(mysqli_query($mysqli, "SELECT " . implode(', ', array_map(function ($v) { return "COALESCE(SUM({$v['where']}), 0)"; }, $views)) . " FROM contracts $joins WHERE 1 $filters")); $counts = array_combine(array_keys($views), array_map('intval', $row)); // The figures along the top - everything in this scope, whatever the search $soon = $views['soon']['where']; $stats = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COALESCE(SUM(contract_status = 'Active'), 0) AS active, COALESCE(SUM($soon AND contract_auto_renew = 0), 0) AS ending, COALESCE(SUM($soon AND contract_auto_renew = 1), 0) AS renewing, COALESCE(SUM(contract_status = 'Draft'), 0) AS draft FROM contracts WHERE contract_archived_at IS NULL $scope_query $client_query")); } $filter_url = function ($changes) { $params = array_merge($_GET, $changes); unset($params['page']); return '?' . http_build_query(array_filter($params, function ($v) { return $v !== '' && $v !== null; })); }; $sort_link = function ($column, $label) use ($url_query_strings_sort, $sort, $disp, $order_icon) { return '' . $label . ($sort === $column ? " $order_icon" : '') . ''; }; $add_url = 'modals/contract/contract_add.php' . ($client_url ? "?client_id=$client_id" : ''); $csrf = $_SESSION['csrf_token']; ?>
In force
Active contracts
Ending soon
Won't renew themselves
Renewing soon
Time to review them with the client
Drafts
Not in force yet

Contracts

· · Signed · left
Not started
= date('Y-m-d')) { ?>
Notice by
No one' ?>
'contracts', 'icon' => 'fa-file-contract', 'filtered' => (bool) $q || $type_filter !== '', 'views' => ['show'], 'view' => emptyStatePill($views, $view, 'active', ['soon']), 'text' => 'The agreement with each client - what it covers, its SLAs and rates, and when it renews.', 'actions' => $can_edit ? [['label' => 'New Contract', 'modal' => $add_url, 'size' => 'lg']] : [], ]; require_once "../includes/filter_footer.php"; ?>