mirror of
https://github.com/itflow-org/itflow
synced 2026-11-11 15:07:24 +00:00
343 lines
24 KiB
PHP
343 lines
24 KiB
PHP
<?php
|
|
|
|
/*
|
|
* Recurring Expenses - what the business is committed to paying, month in,
|
|
* month out: rent, colocation, licensing, insurance, leases.
|
|
*
|
|
* Along the top: what the running ones come to a month (quarterly ones as a
|
|
* third, yearly as a twelfth), what is recorded over the next 30 days, how
|
|
* many are running, and how many need a look - running, but with a next
|
|
* date that has passed. Pills: Active (the default), Next 7 days, Late,
|
|
* Paused, Ended and All. Filter by vendor, category and client. A row opens
|
|
* its quick look, with Record Now, Pause and the expenses it recorded.
|
|
*/
|
|
|
|
// Default Column Sortby/Order Filter
|
|
$sort = "recurring_expense_next_date";
|
|
$order = "ASC";
|
|
|
|
require_once "includes/inc_all.php";
|
|
|
|
// Perms
|
|
enforceUserPermission('module_financial');
|
|
|
|
$can_edit = lookupUserPermission('module_financial') >= 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;
|
|
|
|
?>
|
|
|
|
<!-- What is committed -->
|
|
<div class="row g-3 mb-3">
|
|
<div class="col-sm-6 col-xl-3">
|
|
<a class="itflow-billing-stat" href="<?= escapeHtml($filter_url(['status' => 'active'])) ?>">
|
|
<div class="itflow-billing-stat-label"><i class="fas fa-sync-alt me-1"></i>A month</div>
|
|
<div class="itflow-billing-stat-value"><?= $stat_money($money['monthly']) ?></div>
|
|
<div class="itflow-billing-stat-note"><?= $stat_money($money['monthly'] * 12) ?> a year</div>
|
|
</a>
|
|
</div>
|
|
<div class="col-sm-6 col-xl-3">
|
|
<a class="itflow-billing-stat <?= $status === 'soon' ? 'active' : '' ?>" href="<?= escapeHtml($filter_url(['status' => 'soon'])) ?>">
|
|
<div class="itflow-billing-stat-label"><i class="fas fa-calendar-alt me-1"></i>Next 30 days</div>
|
|
<div class="itflow-billing-stat-value"><?= $stat_money($soon_amount) ?></div>
|
|
<div class="itflow-billing-stat-note"><?= $soon_runs ?> to be recorded</div>
|
|
</a>
|
|
</div>
|
|
<div class="col-sm-6 col-xl-3">
|
|
<a class="itflow-billing-stat <?= $status === 'active' ? 'active' : '' ?>" href="<?= escapeHtml($filter_url(['status' => 'active'])) ?>">
|
|
<div class="itflow-billing-stat-label"><i class="fas fa-play me-1"></i>Running</div>
|
|
<div class="itflow-billing-stat-value"><?= intval($money['running']) ?></div>
|
|
<div class="itflow-billing-stat-note"><?= intval($money['stopped']) ?> paused or ended</div>
|
|
</a>
|
|
</div>
|
|
<div class="col-sm-6 col-xl-3">
|
|
<a class="itflow-billing-stat <?= $status === 'late' ? 'active' : '' ?>" href="<?= escapeHtml($filter_url(['status' => 'late'])) ?>">
|
|
<div class="itflow-billing-stat-label"><i class="fas fa-exclamation-triangle me-1"></i>Need a look</div>
|
|
<div class="itflow-billing-stat-value <?= $money['late'] ? 'text-danger-emphasis' : '' ?>"><?= intval($money['late']) ?></div>
|
|
<div class="itflow-billing-stat-note"><?= $money['late'] ? 'Next date passed' : 'All on schedule' ?></div>
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card">
|
|
<div class="card-header bg-dark py-2">
|
|
<h3 class="card-title mt-2"><i class="fas fa-fw fa-redo-alt me-2"></i>Recurring Expenses</h3>
|
|
<div class="card-tools">
|
|
<div class="btn-group">
|
|
<?php if ($can_edit) { ?>
|
|
<button type="button" class="btn btn-primary ajax-modal" data-modal-size="lg" data-modal-url="modals/recurring_expense/recurring_expense_add.php<?= $vendor_filter ? "?vendor_id=$vendor_filter" : '' ?>"><i class="fas fa-plus me-2"></i>New Recurring Expense</button>
|
|
<?php } ?>
|
|
<button type="button" class="btn btn-primary dropdown-toggle <?= $can_edit ? 'dropdown-toggle-split' : '' ?>" data-bs-toggle="dropdown"><?= $can_edit ? '' : '<i class="fas fa-ellipsis-h"></i>' ?></button>
|
|
<div class="dropdown-menu dropdown-menu-end">
|
|
<a class="dropdown-item" href="expenses.php"><i class="fa fa-fw fa-shopping-cart text-secondary me-2"></i>Expenses</a>
|
|
<?php if (reportCanOpen('expense_by_vendor')) { ?>
|
|
<a class="dropdown-item" href="reports/expense_by_vendor.php"><i class="fa fa-fw fa-chart-bar text-secondary me-2"></i>Spend by Vendor</a>
|
|
<?php } ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-header py-3">
|
|
<form autocomplete="off">
|
|
<input type="hidden" name="status" value="<?= escapeHtml($status) ?>">
|
|
<div class="row g-2 align-items-center">
|
|
<div class="col-lg-3 col-md-6">
|
|
<div class="input-group">
|
|
<input type="search" class="form-control" name="q" value="<?php if (isset($q)) { echo stripslashes(escapeHtml($q)); } ?>" placeholder="Search recurring expenses" title="Vendor, description, reference, amount, client, category">
|
|
<button class="btn btn-dark" title="Search"><i class="fa fa-search"></i></button>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<select class="form-select select2" name="vendor" onchange="this.form.submit()" aria-label="Vendor">
|
|
<option value="">- Any vendor -</option>
|
|
<?php
|
|
$sql_filter = mysqli_query($mysqli, "SELECT vendor_id, vendor_name, vendor_description FROM vendors
|
|
WHERE EXISTS (SELECT 1 FROM recurring_expenses WHERE recurring_expense_vendor_id = vendor_id AND recurring_expense_archived_at IS NULL) ORDER BY vendor_name ASC");
|
|
while ($row = mysqli_fetch_assoc($sql_filter)) {
|
|
$option_id = intval($row['vendor_id']); ?>
|
|
<option <?= $vendor_filter === $option_id ? 'selected' : '' ?> value="<?= $option_id ?>"<?= selectOptionVendor($row['vendor_name'], $row['vendor_description']) ?>><?= escapeHtml($row['vendor_name']) ?></option>
|
|
<?php } ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<select class="form-select select2" name="category" onchange="this.form.submit()" aria-label="Category">
|
|
<option value="">- Any category -</option>
|
|
<?= categoryFilterOptionsHtml('Expense', $category_filter, "SELECT DISTINCT recurring_expense_category_id FROM recurring_expenses WHERE recurring_expense_archived_at IS NULL") ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-lg-3 col-md-6">
|
|
<select class="form-select select2" name="client" onchange="this.form.submit()" aria-label="Client">
|
|
<option value="">- Any client -</option>
|
|
<?php
|
|
$sql_filter = mysqli_query($mysqli, "SELECT client_id, client_name, client_abbreviation FROM clients
|
|
WHERE EXISTS (SELECT 1 FROM recurring_expenses WHERE recurring_expense_client_id = client_id AND recurring_expense_archived_at IS NULL) " . clientScopeSql('clients.client_id') . " ORDER BY client_name ASC");
|
|
while ($row = mysqli_fetch_assoc($sql_filter)) {
|
|
$option_id = intval($row['client_id']); ?>
|
|
<option <?= $client_filter === $option_id ? 'selected' : '' ?> value="<?= $option_id ?>"<?= selectOptionClient($row['client_id'], $row['client_name'], $row['client_abbreviation'] ?? '') ?>><?= escapeHtml($row['client_name']) ?></option>
|
|
<?php } ?>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<nav class="nav nav-pills itflow-asset-tabs mt-2 flex-nowrap overflow-auto">
|
|
<?php foreach ($statuses as $key => $s) {
|
|
$alarm = $key === 'late' && $counts[$key]; ?>
|
|
<a class="nav-link text-nowrap <?= $status === $key ? 'active' : '' ?>" href="<?= escapeHtml($filter_url(['status' => $key])) ?>"<?= !empty($s['title']) ? ' title="' . escapeHtml($s['title']) . '"' : '' ?>>
|
|
<?php if (!empty($s['icon'])) { ?><i class="fas fa-fw <?= $s['icon'] ?> me-1"></i><?php } ?><?= $s['label'] ?>
|
|
<span class="badge rounded-pill ms-1 <?= $alarm ? 'text-bg-danger' : '' ?>"><?= $counts[$key] ?></span>
|
|
</a>
|
|
<?php } ?>
|
|
</nav>
|
|
</div>
|
|
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0 itflow-billing-table">
|
|
<thead class="<?= $num_rows[0] ? '' : 'd-none' ?> text-nowrap table-light">
|
|
<tr>
|
|
<th class="ps-3"><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=vendor_name&order=<?= $disp ?>">Vendor <?php if ($sort == 'vendor_name') { echo $order_icon; } ?></a></th>
|
|
<th><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=category_name&order=<?= $disp ?>">Category <?php if ($sort == 'category_name') { echo $order_icon; } ?></a></th>
|
|
<th><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=client_name&order=<?= $disp ?>">Client <?php if ($sort == 'client_name') { echo $order_icon; } ?></a></th>
|
|
<th class="text-end"><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=recurring_expense_amount&order=<?= $disp ?>">Amount <?php if ($sort == 'recurring_expense_amount') { echo $order_icon; } ?></a></th>
|
|
<th class="text-end"><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=monthly&order=<?= $disp ?>">A month <?php if ($sort == 'monthly') { echo $order_icon; } ?></a></th>
|
|
<th><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=recurring_expense_next_date&order=<?= $disp ?>">Next <?php if ($sort == 'recurring_expense_next_date') { echo $order_icon; } ?></a></th>
|
|
<th><a class="text-reset text-decoration-none" href="?<?= $url_query_strings_sort ?>&sort=recurring_expense_last_sent&order=<?= $disp ?>">Last <?php if ($sort == 'recurring_expense_last_sent') { echo $order_icon; } ?></a></th>
|
|
<th></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($recurring_expenses as $row) {
|
|
$id = intval($row['recurring_expense_id']);
|
|
$row_state = recurringExpenseState($row);
|
|
$row_currency = (string) $row['recurring_expense_currency_code'];
|
|
$row_next = (string) $row['recurring_expense_next_date'];
|
|
$row_open = 'data-modal-size="lg" data-modal-url="modals/recurring_expense/recurring_expense.php?id=' . $id . '"';
|
|
$row_post = function ($action, $extra = '') use ($id) {
|
|
return "post.php?$action=$id$extra&csrf_token=" . $_SESSION['csrf_token'];
|
|
};
|
|
?>
|
|
<tr class="<?= $row_state === 'active' ? '' : 'text-body-secondary' ?>">
|
|
<td class="ps-3">
|
|
<div class="d-flex align-items-center gap-1">
|
|
<?= vendorTile((string) $row['vendor_name'], 'xs') ?>
|
|
<a class="fw-semibold ajax-modal text-truncate" style="max-width: 16rem;" href="#" <?= $row_open ?>><?= escapeHtml($row['vendor_name'] ?: 'No vendor') ?></a>
|
|
</div>
|
|
<div class="small text-body-secondary text-truncate" style="max-width: 18rem;" title="<?= escapeHtml((string) $row['recurring_expense_description']) ?>"><?= escapeHtml((string) $row['recurring_expense_description']) ?: ' ' ?></div>
|
|
</td>
|
|
<td><div class="text-truncate" style="max-width: 11rem;" title="<?= escapeHtml((string) $row['category_name']) ?>"><?= expenseCategoryDot($row['category_color'], $row['category_icon'] ?? '') ?><?= escapeHtml($row['category_name'] ?: '-') ?></div></td>
|
|
<td>
|
|
<?php if (intval($row['recurring_expense_client_id'])) { ?>
|
|
<div class="text-truncate" style="max-width: 10rem;"><a class="text-reset" href="<?= escapeHtml($filter_url(['client' => intval($row['recurring_expense_client_id'])])) ?>"><?= escapeHtml($row['client_name']) ?></a></div>
|
|
<?php if ($row['recurring_invoice_number'] !== null) { ?>
|
|
<div class="small text-success-emphasis text-truncate" style="max-width: 10rem;" title="Covered by their recurring invoice"><i class="fas fa-shield-alt me-1"></i>Covered by <?= escapeHtml($row['recurring_invoice_prefix'] . $row['recurring_invoice_number']) ?></div>
|
|
<?php } elseif (intval($row['recurring_expense_billable'])) { ?>
|
|
<div class="small text-warning-emphasis" title="Each one it records is billed on to them at <?= escapeHtml(rtrim(rtrim(number_format(floatval($row['recurring_expense_markup']), 2, '.', ''), '0'), '.')) ?>% markup"><i class="fas fa-file-invoice-dollar me-1"></i>Billed on</div>
|
|
<?php } ?>
|
|
<?php } else { ?>
|
|
<span class="text-body-secondary">-</span>
|
|
<?php } ?>
|
|
</td>
|
|
<td class="text-end itflow-money text-nowrap">
|
|
<span class="fw-semibold"><?= escapeHtml(billingMoney($row['recurring_expense_amount'], $row_currency)) ?></span>
|
|
<div class="small text-body-secondary"><?= escapeHtml(recurringInvoiceFrequencies()[$row['recurring_expense_frequency']] ?? 'Monthly') ?></div>
|
|
</td>
|
|
<td class="text-end itflow-money text-nowrap"><?= escapeHtml(billingMoney($row['monthly'], $row_currency)) ?></td>
|
|
<td class="text-nowrap">
|
|
<?= $row_state === 'ended' ? '' : escapeHtml($row_next) ?>
|
|
<div><?= recurringExpenseNextPill($row) ?></div>
|
|
<?php if ($row['recurring_expense_end_date'] && $row_state !== 'ended') { ?><div class="small text-body-secondary" title="Its last run is on or before this date">Ends <?= escapeHtml($row['recurring_expense_end_date']) ?></div><?php } ?>
|
|
</td>
|
|
<td class="text-nowrap small">
|
|
<?php if ($row['recurring_expense_last_sent']) { ?>
|
|
<a class="text-reset" href="expenses.php?recurring_expense_id=<?= $id ?>" title="The expenses it recorded"><?= escapeHtml($row['recurring_expense_last_sent']) ?></a>
|
|
<?php } else { ?>
|
|
<span class="text-body-secondary">Not yet</span>
|
|
<?php } ?>
|
|
</td>
|
|
<td class="text-end">
|
|
<div class="dropdown dropstart">
|
|
<button class="btn btn-sm btn-light" title="More actions" type="button" data-bs-toggle="dropdown"><i class="fas fa-fw fa-ellipsis-v"></i></button>
|
|
<div class="dropdown-menu">
|
|
<a class="dropdown-item ajax-modal" href="#" <?= $row_open ?>><i class="fas fa-fw fa-eye text-secondary me-2"></i>Open</a>
|
|
<a class="dropdown-item" href="expenses.php?recurring_expense_id=<?= $id ?>"><i class="fas fa-fw fa-shopping-cart text-secondary me-2"></i>Expenses Recorded</a>
|
|
<?php if ($can_edit) { ?>
|
|
<div class="dropdown-divider"></div>
|
|
<?php if ($row_state !== 'ended') { ?>
|
|
<a class="dropdown-item confirm-link" href="<?= $row_post('recurring_expense_record', '&run=' . $row_next) ?>"
|
|
data-confirm-title="Record the <?= escapeHtml(date('M j', strtotime($row_next))) ?> run now?"
|
|
data-confirm-text="An expense of <?= escapeHtml(billingMoney($row['recurring_expense_amount'], $row_currency)) ?>, and the next one moves to <?= escapeHtml(date('M j, Y', strtotime(recurringExpenseAfter($row, $row_next)))) ?>." data-confirm-button="Record">
|
|
<i class="fas fa-fw fa-bolt text-secondary me-2"></i>Record Now
|
|
</a>
|
|
<?php } ?>
|
|
<?php if ($row_state === 'active' && $row_next < date('Y-m-d')) { ?>
|
|
<a class="dropdown-item confirm-link" href="<?= $row_post('recurring_expense_catch_up') ?>"
|
|
data-confirm-title="Skip the missed runs?" data-confirm-text="The next date moves on to <?= escapeHtml(recurringExpenseCatchUp($row)) ?>. Nothing is recorded for the runs it missed." data-confirm-button="Move on">
|
|
<i class="fas fa-fw fa-forward text-secondary me-2"></i>Move On to <?= escapeHtml(recurringExpenseCatchUp($row)) ?>
|
|
</a>
|
|
<?php } ?>
|
|
<?php if ($row_state === 'active') { ?>
|
|
<a class="dropdown-item" href="<?= $row_post('recurring_expense_set_status', '&status=0') ?>"><i class="fas fa-fw fa-pause text-secondary me-2"></i>Pause</a>
|
|
<?php } elseif ($row_state === 'paused') { ?>
|
|
<a class="dropdown-item" href="<?= $row_post('recurring_expense_set_status', '&status=1') ?>"><i class="fas fa-fw fa-play text-secondary me-2"></i>Resume</a>
|
|
<?php } ?>
|
|
<a class="dropdown-item ajax-modal" href="#" data-modal-size="lg" data-modal-url="modals/recurring_expense/recurring_expense_edit.php?id=<?= $id ?>"><i class="fas fa-fw fa-edit text-secondary me-2"></i>Edit</a>
|
|
<?php } ?>
|
|
<?php if ($can_delete) { ?>
|
|
<div class="dropdown-divider"></div>
|
|
<a class="dropdown-item text-danger text-bold confirm-link" href="<?= $row_post('delete_recurring_expense') ?>"
|
|
data-confirm-text="<?= escapeHtml(recurringExpenseLabel($row)) ?> goes for good. The expenses it recorded stay.">
|
|
<i class="fas fa-fw fa-trash me-2"></i>Delete
|
|
</a>
|
|
<?php } ?>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
<?php } ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php
|
|
$empty_state = [
|
|
'thing' => '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";
|
|
?>
|
|
</div>
|
|
|
|
<?php if (!empty($_GET['open'])) { ?>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
var open = document.createElement('a');
|
|
open.className = 'ajax-modal';
|
|
open.href = '#';
|
|
open.dataset.modalSize = 'lg';
|
|
open.dataset.modalUrl = 'modals/recurring_expense/recurring_expense.php?id=<?= intval($_GET['open']) ?>';
|
|
document.body.appendChild(open);
|
|
open.click();
|
|
open.remove();
|
|
});
|
|
</script>
|
|
<?php } ?>
|
|
|
|
<?php require_once "../includes/footer.php";
|