= 2; $can_delete = lookupUserPermission('module_financial') >= 3; $vendor_filter = intval($_GET['vendor'] ?? 0); $category_filter = intval($_GET['category'] ?? 0); $client_filter = intval($_GET['client'] ?? 0); $statuses = recurringExpenseShows(); $status = isset($statuses[$_GET['status'] ?? '']) ? (string) $_GET['status'] : 'active'; $status_query = $statuses[$status]['where'] ? 'AND ' . $statuses[$status]['where'] : ''; // Only these sort - filter_header.php hands through any lowercase word $sortable_columns = ['recurring_expense_next_date' => 'recurring_expense_next_date', 'vendor_name' => 'vendor_name', 'category_name' => 'category_name', 'client_name' => 'client_name', 'recurring_expense_amount' => 'recurring_expense_amount', 'monthly' => 'monthly', 'recurring_expense_last_sent' => 'recurring_expense_last_sent']; if (!isset($sortable_columns[$sort])) { $sort = 'recurring_expense_next_date'; } $joins = "LEFT JOIN vendors ON recurring_expense_vendor_id = vendor_id LEFT JOIN categories ON recurring_expense_category_id = category_id LEFT JOIN accounts ON recurring_expense_account_id = account_id LEFT JOIN clients ON recurring_expense_client_id = client_id"; $where = recurringExpenseFiltersSql($_GET); $monthly_sql = expenseRecurringMonthlySql(); $sql = mysqli_query($mysqli, "SELECT SQL_CALC_FOUND_ROWS recurring_expenses.*, vendor_name, vendor_archived_at, category_name, category_color, category_icon, account_name, client_name, $monthly_sql AS monthly, recurring_invoice_prefix, recurring_invoice_number FROM recurring_expenses $joins LEFT JOIN recurring_invoices ON recurring_invoice_id = recurring_expense_recurring_invoice_id WHERE $where $status_query ORDER BY {$sortable_columns[$sort]} $order, recurring_expense_id ASC LIMIT $record_from, $record_to"); $num_rows = mysqli_fetch_row(mysqli_query($mysqli, "SELECT FOUND_ROWS()")); $recurring_expenses = []; while ($row = mysqli_fetch_assoc($sql)) { $recurring_expenses[] = $row; } // The pills - over what the filters leave $count_sql = []; foreach ($statuses as $key => $s) { $count_sql[] = $s['where'] === '' ? 'COUNT(*)' : "COALESCE(SUM({$s['where']}), 0)"; } $row = mysqli_fetch_row(mysqli_query($mysqli, "SELECT " . implode(', ', $count_sql) . " FROM recurring_expenses $joins WHERE $where")); $counts = []; foreach (array_keys($statuses) as $i => $key) { $counts[$key] = intval($row[$i]); } // The money along the top - every recurring expense the agent can see, not narrowed by search or pill $scope = "recurring_expense_archived_at IS NULL " . clientScopeSql('recurring_expense_client_id'); $money = mysqli_fetch_assoc(mysqli_query($mysqli, "SELECT COALESCE(SUM(CASE WHEN recurring_expense_status = 1 THEN $monthly_sql END), 0) AS monthly, COALESCE(SUM(recurring_expense_status = 1), 0) AS running, COALESCE(SUM(recurring_expense_status = 0), 0) AS stopped, COALESCE(SUM(recurring_expense_status = 1 AND recurring_expense_next_date < CURDATE()), 0) AS late FROM recurring_expenses WHERE $scope")); $soon_to = date('Y-m-d', strtotime('+30 days')); $soon_amount = 0.0; $soon_runs = 0; $sql_soon = mysqli_query($mysqli, "SELECT recurring_expenses.* FROM recurring_expenses WHERE $scope AND recurring_expense_status = 1 AND recurring_expense_next_date <= '$soon_to'"); while ($soon = mysqli_fetch_assoc($sql_soon)) { $runs = count(recurringExpenseRunsUntil($soon, $soon_to)); $soon_runs += $runs; $soon_amount += $runs * floatval($soon['recurring_expense_amount']); } $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; })); }; $stat_money = function ($amount) use ($session_company_currency) { return escapeHtml(billingMoney($amount, $session_company_currency)); }; $any_filter = $q || $vendor_filter || $category_filter || $client_filter; ?>
A month
a year
Next 30 days
to be recorded
Running
paused or ended
Need a look

Recurring Expenses

Vendor Category Client Amount A month Next Last
>
Covered by
Billed on
-
Ends
Not yet
'recurring expenses', 'icon' => 'fa-redo-alt', 'filtered' => $any_filter, 'views' => ['status'], 'view' => emptyStatePill($statuses, $status, 'active', ['late']), 'text' => 'Rent, colocation, licensing and insurance - recorded for you each time they come round.', 'actions' => $can_edit ? [['label' => 'New Recurring Expense', 'modal' => 'modals/recurring_expense/recurring_expense_add.php' . ($vendor_filter ? "?vendor_id=$vendor_filter" : ''), 'size' => 'lg']] : [], ]; require_once "../includes/filter_footer.php"; ?>