Files
itflow/agent/modals/expense/expense_reimbursement.php
johnnyq df668d83e6 Accounts Reconcile: reconcile an account against its bank or card statement from the account's menu on Accounts or Transactions - enter the statement's ending date and balance (what is owed, for a card) and notes, starting from where the last statement ended or the opening balance, with lines brought in from bank statements pre-ticked; tick what cleared with the cleared balance and difference updating as you go, each tick saved immediately so a statement can be finished later, pills for money in, money out, not ticked and ticked, search, tick and untick all shown, a bar keeping the difference and Finish in view, and Finish only once the difference is nothing; change the statement, discard it, or add a missing line with New Expense, New Income or New Transfer starting on the account; a history of reconciled statements with ending balance, lines cleared, money in and out and who reconciled it, with Undo on the latest putting it back in progress with its ticks; Transactions marks cleared lines linking to their statement, adds an Uncleared pill and a filter for one statement's lines, the export adds a Cleared column, and Accounts shows where each account is reconciled to; a cleared payment, other income, expense, transfer or reimbursement keeps its amount, date and account and can't be deleted until its statement is undone, which also blocks deleting its invoice or client (including through the API), refunding a cleared Stripe payment, bulk set account and bulk delete on cleared lines, and undoing a cleared reimbursement, with quick looks and edit windows showing where it cleared; the opening balance locks once an account has a reconciled statement and a ticked line moved to another account comes off its statement; reconciling needs write Financial access and undoing full access; new functions/reconcile.php, agent/reconcile.php, agent/post/reconcile.php and js/reconcile.js with ticking through agent/ajax.php; database 3.0.8 adds account_reconciliations and the reconciliation id on payments, revenues and expenses; demo data reconciles Operating Checking and the Business Visa monthly through last month; CHANGELOG updated
2026-10-16 23:12:22 -04:00

94 lines
5.6 KiB
PHP

<?php
/*
* A reimbursement's quick look - who was paid back, how much, when, from
* which account and how, who entered it, and the expenses it paid back.
* Undo takes the money out of the account away and makes the expenses to
* reimburse again. Opened from an expense it paid back and Transactions.
*/
require_once '../../../includes/modal_header.php';
enforceUserPermission('module_financial');
$row = reimbursementRow(intval($_GET['id'] ?? 0));
if (!$row) {
exit(json_encode(['error' => 'That reimbursement no longer exists - it was undone.']));
}
$reimbursement_id = intval($row['reimbursement_id']);
$cleared = reconcileLock('expense', $row['reimbursement_expense_id']);
$currency = (string) $row['reimbursement_currency_code'];
$expenses = reimbursementExpenses($reimbursement_id);
$can_undo = lookupUserPermission('module_financial') >= 3;
$expenses_total = array_sum(array_map(function ($e) { return floatval($e['expense_amount']); }, $expenses));
ob_start();
?>
<div class="modal-header bg-dark" data-bs-theme="dark">
<div class="d-flex align-items-center gap-3 min-w-0 flex-grow-1">
<span class="itflow-asset-icon itflow-asset-icon-lg bg-success-subtle text-success-emphasis" aria-hidden="true"><i class="fas fa-hand-holding-usd"></i></span>
<div class="min-w-0 flex-grow-1">
<h5 class="modal-title fw-semibold text-break">Paid back to <?= escapeHtml($row['user_name'] ?: 'an agent since deleted') ?></h5>
<div class="small text-body-secondary mt-1"><?= escapeHtml(date('M j, Y', strtotime($row['reimbursement_date']))) ?> · <?= count($expenses) ?> expense<?= count($expenses) === 1 ? '' : 's' ?></div>
</div>
<div class="fs-4 fw-semibold itflow-money text-white"><?= escapeHtml(billingMoney($row['reimbursement_amount'], $currency)) ?></div>
</div>
<button type="button" class="btn-close btn-close-white ms-3" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div class="row g-2 itflow-asset-glance">
<div class="col-sm-6">
<div class="itflow-glance-item" title="Paid from">
<i class="fas fa-fw fa-piggy-bank"></i>
<span><?= escapeHtml($row['account_name'] ?: 'An account since deleted') ?><?= $row['reimbursement_payment_method'] ? ' <span class="text-body-secondary">&middot; ' . escapeHtml($row['reimbursement_payment_method']) . '</span>' : '' ?></span>
</div>
<?php if ($row['reimbursement_reference']) { ?>
<div class="itflow-glance-item" title="Reference">
<i class="fas fa-fw fa-hashtag"></i>
<span class="font-monospace text-break"><?= escapeHtml($row['reimbursement_reference']) ?></span>
</div>
<?php } ?>
</div>
<div class="col-sm-6">
<div class="itflow-glance-item" title="Entered">
<i class="fas fa-fw fa-clock"></i>
<span><span title="<?= escapeHtml($row['reimbursement_created_at']) ?>"><?= timeAgo($row['reimbursement_created_at']) ?></span><?php if ($row['created_by_name']) { ?> <span class="text-body-secondary">by <?= escapeHtml($row['created_by_name']) ?></span><?php } ?></span>
</div>
<?= reconcileGlanceHtml($cleared) ?>
</div>
</div>
<div class="mt-3">
<div class="small fw-semibold text-uppercase text-body-secondary mb-1">What it paid back</div>
<?php foreach ($expenses as $expense) { ?>
<div class="d-flex justify-content-between gap-2 small py-1 border-bottom">
<a class="text-truncate ajax-modal" href="#" data-modal-size="lg" data-modal-url="modals/expense/expense.php?id=<?= intval($expense['expense_id']) ?>">
<span class="text-body-secondary me-1"><?= escapeHtml($expense['expense_date']) ?></span><?= escapeHtml($expense['vendor_name'] ?: 'Expense') ?><?= trim((string) $expense['expense_description']) !== '' ? ' - ' . escapeHtml(truncate(strtok((string) $expense['expense_description'], "\n"), 50)) : '' ?>
</a>
<span class="itflow-money text-nowrap"><?= escapeHtml(billingMoney($expense['expense_amount'], $expense['expense_currency_code'])) ?></span>
</div>
<?php } ?>
<?php if (!$expenses) { ?>
<div class="small text-body-secondary">The expenses it paid back have since been deleted.</div>
<?php } elseif (abs($expenses_total - floatval($row['reimbursement_amount'])) >= 0.005) { ?>
<div class="small text-warning-emphasis mt-2"><i class="fas fa-exclamation-triangle me-1"></i>They come to <?= escapeHtml(billingMoney($expenses_total, $currency)) ?> now - one was changed or deleted after it was paid back.</div>
<?php } ?>
</div>
</div>
<div class="modal-footer">
<?php if ($can_undo && $cleared) { ?>
<span class="me-auto"><?= reconcileLockedButtonHtml($cleared, 'Undo', 'fa-undo-alt', 'undo it') ?></span>
<?php } elseif ($can_undo) { ?>
<a class="btn btn-outline-danger confirm-link me-auto" href="post.php?expense_reimbursement_delete=<?= $reimbursement_id ?>&amp;csrf_token=<?= $_SESSION['csrf_token'] ?>"
data-confirm-text="The <?= escapeHtml(billingMoney($row['reimbursement_amount'], $currency)) ?> comes back off <?= escapeHtml($row['account_name'] ?: 'the account') ?>, and its expenses are to reimburse again."><i class="fas fa-undo-alt me-2"></i>Undo</a>
<?php } ?>
<button type="button" class="btn btn-light" data-bs-dismiss="modal"><i class="fa fa-times me-2"></i>Close</button>
</div>
<?php
require_once '../../../includes/modal_footer.php';