= 2; $can_delete = lookupUserPermission('module_financial') >= 3; $can_sales = lookupUserPermission('module_sales') >= 1; $vendor_filter = intval($_GET['vendor'] ?? 0); $category_filter = intval($_GET['category'] ?? 0); $account_filter = intval($_GET['account'] ?? 0); $client_filter = intval($_GET['client'] ?? 0); $method_filter = trim((string) ($_GET['method'] ?? '')); $recurring_filter = intval($_GET['recurring_expense_id'] ?? 0); $recurring_filter_row = $recurring_filter ? recurringExpenseRow($recurring_filter) : null; $paid_by_filter = intval($_GET['paid_by'] ?? 0); $shows = expenseShows(); $show = isset($shows[$_GET['show'] ?? '']) ? (string) ($_GET['show'] ?? '') : ''; // Only these sort - filter_header.php hands through any lowercase word $sortable_columns = ['expense_date' => 'expense_date', 'vendor_name' => 'vendor_name', 'category_name' => 'category_name', 'client_name' => 'client_name', 'account_name' => 'account_name', 'expense_amount' => 'expense_amount', 'expense_created_at' => 'expense_created_at']; if (!isset($sortable_columns[$sort])) { $sort = 'expense_date'; } // Everything but the pill, then the pill - the pill counts are over what the rest leave $filter_src = array_merge($_GET, ['dtf' => $dtf, 'dtt' => $dtt, 'show' => '']); $where = expenseFiltersSql($filter_src); $show_query = $shows[$show]['where'] ? "AND {$shows[$show]['where']}" : ''; $joins = expenseJoinsSql(); $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS expenses.*, vendor_name, vendor_archived_at, category_name, category_color, category_icon, account_name, client_name, user_name, invoice_prefix, invoice_number, (SELECT payer.user_name FROM users AS payer WHERE payer.user_id = expense_paid_by) AS paid_by_name FROM expenses $joins LEFT JOIN invoices ON invoice_id = expense_invoice_id WHERE $where $show_query ORDER BY {$sortable_columns[$sort]} $order, expense_id DESC LIMIT $record_from, $record_to"); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $expenses = []; while ($row = mysqli_fetch_assoc($sql)) { $expenses[] = $row; } // The pills, and the total of what is listed $count_sql = []; foreach ($shows as $key => $s) { $count_sql[] = $key === '' ? 'COUNT(*)' : "COALESCE(SUM({$s['where']}), 0)"; } $row = mysqli_fetch_row(mysqli_query($mysqli, "SELECT " . implode(', ', $count_sql) . ", COALESCE(SUM(CASE WHEN 1 $show_query THEN expense_amount END), 0) FROM expenses $joins WHERE $where")); $counts = []; foreach (array_keys($shows) as $i => $key) { $counts[$key] = intval($row[$i]); } $listed_total = floatval($row[count($shows)]); $stats = expenseStats(); $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; })); }; $date_url = function ($from, $to, $changes = []) use ($filter_url) { return $filter_url(array_merge(['canned_date' => 'custom', 'dtf' => $from, 'dtt' => $to], $changes)); }; $stat_money = function ($amount) use ($session_company_currency) { return escapeHtml(billingMoney($amount, $session_company_currency)); }; // More filters open when one of them is set $more_filters = $account_filter || $method_filter !== ''; $any_filter = $q || $vendor_filter || $category_filter || $account_filter || $client_filter || $method_filter !== '' || $recurring_filter || $paid_by_filter || $show !== '' || $dtf !== '1970-01-01'; // Who is owed for what they paid personally - above the list on To reimburse $owed = $show === 'to_reimburse' ? expenseToReimburse($paid_by_filter) : []; // This month against the same days of last month $month_change = $stats['last_to_date'] > 0 ? round(($stats['month'] - $stats['last_to_date']) / $stats['last_to_date'] * 100) : null; ?>
This month
% on the same days of in
so far
expense · a month
Recurring
a month from running · a year
No receipt, 90 days

Expenses

Recorded by ' . escapeHtml(recurringExpenseLabel($recurring_filter_row)) . '' : 'a recurring expense' ?> Clear
Paid personally by Clear
$agent) { ?>
is owed for expense 1 ? ', the oldest ' . $agent['oldest'] . ' days ago' : ($agent['oldest'] === 1 ? ', the oldest yesterday' : ' from today') ?>
Date Vendor Category Client Paid from Amount
> true, 'archived' => !empty($row['vendor_archived_at'])]) ?>
Billed Billed
0) { ?>
To billTo bill
-
0) { ?>
To reimburse
Refund
incl. tax
expense count($expenses) ? ' - the total is for all of them, not just this page' : '' ?>
'expenses', 'icon' => 'fa-shopping-cart', 'filtered' => $q || $vendor_filter || $category_filter || $account_filter || $client_filter || $method_filter !== '' || $recurring_filter || $paid_by_filter || $dtf !== '1970-01-01', 'views' => ['show'], 'view' => emptyStatePill($shows, $show, '', ['no_receipt', 'to_bill', 'to_reimburse']), 'text' => 'What the business spends - enter them as they come, or bring in a bank or card statement.', 'actions' => $can_edit ? [ ['label' => 'New Expense', 'modal' => 'modals/expense/expense_add.php' . ($vendor_filter ? "?vendor_id=$vendor_filter" : ''), 'size' => 'lg'], ['label' => 'Import Statement', 'href' => 'expense_import.php', 'icon' => 'fa-file-import'], ] : [], ]; require_once "../includes/filter_footer.php"; ?>