" . escapeHtml($label) . " set up - the first one is recorded on " . escapeHtml(date('M j, Y', strtotime($row['recurring_expense_next_date'])))); redirect(); } if (isset($_POST['edit_recurring_expense'])) { validateCSRFToken(); enforceUserPermission('module_financial', 2); $recurring_expense_id = intval($_POST['recurring_expense_id'] ?? 0); $before = recurringExpenseRow($recurring_expense_id); if (!recurringExpenseSave($_POST, $recurring_expense_id, $error)) { flashAlert($error, 'error'); redirect(); } $row = recurringExpenseRow($recurring_expense_id, false); $label = recurringExpenseLabel($row); $state = recurringExpenseState($row); $changes = []; if (floatval($before['recurring_expense_amount']) != floatval($row['recurring_expense_amount'])) { $changes[] = 'amount from ' . billingMoney($before['recurring_expense_amount'], $before['recurring_expense_currency_code']) . ' to ' . billingMoney($row['recurring_expense_amount'], $row['recurring_expense_currency_code']); } if ($before['recurring_expense_next_date'] !== $row['recurring_expense_next_date']) { $changes[] = "next date from {$before['recurring_expense_next_date']} to {$row['recurring_expense_next_date']}"; } logAudit("Recurring Expense", "Edit", "$session_name edited the recurring expense " . escapeSql($label) . ($changes ? ' - ' . escapeSql(implode(', ', $changes)) : ''), intval($row['recurring_expense_client_id']), $recurring_expense_id); if ($state === 'ended' && recurringExpenseState($before) !== 'ended') { flashAlert("Recurring expense " . escapeHtml($label) . " saved - its end date is before the next one, so it has ended", 'warning'); } elseif ($state === 'active' && recurringExpenseState($before) === 'ended') { flashAlert("Recurring expense " . escapeHtml($label) . " saved and running again - the next one is on " . escapeHtml(date('M j, Y', strtotime($row['recurring_expense_next_date'])))); } else { flashAlert("Recurring expense " . escapeHtml($label) . " saved"); } redirect(); } // Pause (status=0) or Resume (status=1) if (isset($_GET['recurring_expense_set_status'])) { validateCSRFToken(); enforceUserPermission('module_financial', 2); $row = recurringExpenseRow(intval($_GET['recurring_expense_set_status'])); if (!$row) { flashAlert('That recurring expense no longer exists', 'error'); redirect(); } $recurring_expense_id = intval($row['recurring_expense_id']); $status = intval($_GET['status'] ?? 0) === 1 ? 1 : 0; $label = recurringExpenseLabel($row); if ($status === 1 && recurringExpenseEnded($row)) { flashAlert("" . escapeHtml($label) . " ended on " . escapeHtml($row['recurring_expense_end_date']) . " - change its end date in Edit to run it again", 'error'); redirect(); } mysqli_query($mysqli, "UPDATE recurring_expenses SET recurring_expense_status = $status WHERE recurring_expense_id = $recurring_expense_id"); logAudit("Recurring Expense", $status ? "Resume" : "Pause", "$session_name " . ($status ? 'resumed' : 'paused') . " the recurring expense " . escapeSql($label), intval($row['recurring_expense_client_id']), $recurring_expense_id); if ($status && $row['recurring_expense_next_date'] < date('Y-m-d', strtotime('-' . RECURRING_EXPENSE_GRACE_DAYS . ' days'))) { flashAlert("" . escapeHtml($label) . " resumed - its next date has passed, so record the missed runs or move it on", 'warning'); } else { flashAlert("" . escapeHtml($label) . " " . ($status ? 'resumed' : 'paused')); } redirect(); } // Record Now - the next run, or the one &run= names (what the page showed), so pressing it twice records it once if (isset($_GET['recurring_expense_record'])) { validateCSRFToken(); enforceUserPermission('module_financial', 2); $row = recurringExpenseRow(intval($_GET['recurring_expense_record'])); if (!$row) { flashAlert('That recurring expense no longer exists', 'error'); redirect(); } if (recurringExpenseEnded($row)) { flashAlert("" . escapeHtml(recurringExpenseLabel($row)) . " has ended - there is nothing more to record", 'error'); redirect(); } $run = isset($_GET['run']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_GET['run']) ? $_GET['run'] : $row['recurring_expense_next_date']; $expense_id = recurringExpenseRecord(intval($row['recurring_expense_id']), intval($session_user_id), $run, stripslashes($session_name)); if (!$expense_id) { flashAlert("That run of " . escapeHtml(recurringExpenseLabel($row)) . " is already recorded", 'warning'); redirect(); } $after = recurringExpenseRow(intval($row['recurring_expense_id']), false); flashAlert("Recorded " . escapeHtml(expenseLabel(expenseRow($expense_id, false))) . "" . (recurringExpenseEnded($after) ? ' - that was the last one, it has ended' : ' - the next one is on ' . escapeHtml(date('M j, Y', strtotime($after['recurring_expense_next_date']))))); redirect(); } // Move On - skip the missed runs without recording them if (isset($_GET['recurring_expense_catch_up'])) { validateCSRFToken(); enforceUserPermission('module_financial', 2); $row = recurringExpenseRow(intval($_GET['recurring_expense_catch_up'])); if (!$row) { flashAlert('That recurring expense no longer exists', 'error'); redirect(); } $recurring_expense_id = intval($row['recurring_expense_id']); $from = $row['recurring_expense_next_date']; $next = recurringExpenseCatchUp($row); $ends = !empty($row['recurring_expense_end_date']) && $next > $row['recurring_expense_end_date']; mysqli_query($mysqli, "UPDATE recurring_expenses SET recurring_expense_next_date = '$next'" . ($ends ? ', recurring_expense_status = 0' : '') . " WHERE recurring_expense_id = $recurring_expense_id AND recurring_expense_next_date = '" . escapeSql($from) . "'"); logAudit("Recurring Expense", "Move On", "$session_name moved the recurring expense " . escapeSql(recurringExpenseLabel($row)) . " on from $from to $next without recording the missed runs", intval($row['recurring_expense_client_id']), $recurring_expense_id); flashAlert("" . escapeHtml(recurringExpenseLabel($row)) . " moved on to " . escapeHtml(date('M j, Y', strtotime($next))) . ($ends ? ' - past its end date, so it has ended' : '')); redirect(); } if (isset($_GET['delete_recurring_expense'])) { validateCSRFToken(); enforceUserPermission('module_financial', 3); $row = recurringExpenseDelete(intval($_GET['delete_recurring_expense']), $error); if (!$row) { flashAlert($error, 'error'); redirect(); } logAudit("Recurring Expense", "Delete", "$session_name deleted the recurring expense " . escapeSql(recurringExpenseLabel($row)), intval($row['recurring_expense_client_id'])); flashAlert("Recurring expense " . escapeHtml(recurringExpenseLabel($row)) . " deleted - the expenses it recorded stay", 'error'); redirect(); }