Files
cbsnexora/src/app/cashier/end-of-day-report/end-of-day-report.component.html
T

607 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
Copyright since 2025 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<div class="pg eod">
<!-- Toolbar: never printed, because a printed sheet has nothing to click. -->
<div class="pg-head no-print">
<div>
<h1 class="pg-title">End of the Day Report</h1>
<p class="pg-sub">What moved today, whether the cash agrees with the books, and who signs off.</p>
</div>
<div class="pg-toolbar">
<label class="pg-field">
<span>Business date</span>
<input type="date" [(ngModel)]="date" (change)="reload()" />
</label>
<button class="pg-btn pg-btn--ghost" (click)="reload()" [disabled]="loading">
<mat-icon>refresh</mat-icon>
Reload
</button>
<button class="pg-btn pg-btn--primary" (click)="print()" [disabled]="!loaded">
<mat-icon>print</mat-icon>
Print / Save as PDF
</button>
</div>
</div>
@if (loading) {
<div class="pg-empty">Loading the day&rsquo;s figures&hellip;</div>
}
@if (loaded) {
<div class="eod-sheet">
<!-- ── Header ── -->
<div class="eod-sheet__head">
<h2 class="eod-sheet__title">Daily EOD &amp; Transaction Report</h2>
<div class="eod-sheet__meta">
<div class="eod-meta">
<span class="eod-meta__label">Date</span>
<span class="eod-meta__value">{{ date | date: 'dd MMM yyyy' }}</span>
</div>
<div class="eod-meta">
<span class="eod-meta__label">Branch</span>
<span class="eod-meta__value">{{ branchName || '—' }}</span>
</div>
<div class="eod-meta">
<span class="eod-meta__label">Prepared by</span>
<span class="eod-meta__value">{{ preparedBy || '—' }}</span>
</div>
<div class="eod-meta">
<span class="eod-meta__label">Scope</span>
<span class="eod-meta__value">{{ scopedToCashier ? 'My counter' : 'Branch counter' }}</span>
</div>
</div>
</div>
<!-- ── 1. Transaction summary ── -->
<section class="eod-section">
<h3 class="eod-section__title"><span class="eod-section__no">1</span> Transaction Summary</h3>
@if (sectionLines.length) {
<p class="eod-caption">Where the money came from</p>
<table class="pg-table">
<thead>
<tr>
<th>Source</th>
<th class="num">Entries</th>
<th class="num col-in">Money in</th>
<th class="num col-out">Money out</th>
</tr>
</thead>
<tbody>
@for (l of sectionLines; track l.label) {
<tr>
<td>{{ l.label }}</td>
<td class="num">{{ l.count }}</td>
<td class="num col-in">{{ l.credit ? (l.credit | currency: 'INR') : '—' }}</td>
<td class="num col-out">{{ l.debit ? (l.debit | currency: 'INR') : '—' }}</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td><strong>Total</strong></td>
<td class="num">
<strong>{{ txnCount }}</strong>
</td>
<td class="num col-in">
<strong>{{ summaryCreditTotal | currency: 'INR' }}</strong>
</td>
<td class="num col-out">
<strong>{{ summaryDebitTotal | currency: 'INR' }}</strong>
</td>
</tr>
</tfoot>
</table>
<p class="eod-caption eod-caption--spaced">What kind of entries</p>
<table class="pg-table">
<thead>
<tr>
<th>Kind</th>
<th class="num">Entries</th>
<th class="num col-in">Money in</th>
<th class="num col-out">Money out</th>
</tr>
</thead>
<tbody>
@for (l of kindLines; track l.label) {
<tr>
<td>{{ l.label }}</td>
<td class="num">{{ l.count }}</td>
<td class="num col-in">{{ l.credit ? (l.credit | currency: 'INR') : '—' }}</td>
<td class="num col-out">{{ l.debit ? (l.debit | currency: 'INR') : '—' }}</td>
</tr>
}
</tbody>
</table>
<p class="eod-note">
Only entries that actually moved money. Anything still pending is listed at the bottom. These figures match
the Day Book for the same date.
</p>
} @else {
<div class="pg-empty">No transactions on this date.</div>
}
</section>
<!-- ── 2. Cash ──
Movement first, because that is the part every figure here agrees on. A comparison
against what is held is only offered where both sides describe the same period. -->
<section class="eod-section">
<h3 class="eod-section__title"><span class="eod-section__no">2</span> Cash</h3>
@if (scopedToCashier) {
<p class="eod-caption">Your drawer today</p>
<table class="pg-table eod-recon">
<tbody>
<tr>
<td>Cash you took from the vault this morning</td>
<td class="num">{{ openingFloat | currency: 'INR' }}</td>
</tr>
<tr>
<td>Cash you took from members <span class="eod-hint">deposits, including DD cash</span></td>
<td class="num col-in">+{{ cashDeposits | currency: 'INR' }}</td>
</tr>
@if (interCashierIn) {
<tr>
<td>Cash another cashier gave you</td>
<td class="num col-in">+{{ interCashierIn | currency: 'INR' }}</td>
</tr>
}
<tr>
<td>Cash you paid to members <span class="eod-hint">withdrawals</span></td>
<td class="num col-out">−{{ cashWithdrawals | currency: 'INR' }}</td>
</tr>
@if (settledOut) {
<tr>
<td>Cash you handed back to the vault</td>
<td class="num col-out">−{{ settledOut | currency: 'INR' }}</td>
</tr>
}
@if (interCashierOut) {
<tr>
<td>Cash you gave another cashier</td>
<td class="num col-out">−{{ interCashierOut | currency: 'INR' }}</td>
</tr>
}
<tr class="eod-recon__expected">
<td><strong>So your drawer should hold</strong></td>
<td class="num">
@if (expectedCash !== null) {
<strong>{{ expectedCash | currency: 'INR' }}</strong>
} @else {
<span class="eod-blank">&mdash;</span>
}
</td>
</tr>
<tr>
<td><strong>System says you hold</strong></td>
<td class="num">
@if (actualCash !== null) {
<strong>{{ actualCash | currency: 'INR' }}</strong>
} @else {
<span class="eod-blank">nothing recorded</span>
}
</td>
</tr>
@if (variance !== null) {
<tr class="eod-recon__variance" [class]="varianceClass">
<td><strong>Difference</strong></td>
<td class="num">
<strong>{{ variance | currency: 'INR' }}</strong>
</td>
</tr>
}
</tbody>
</table>
@if (variance !== null) {
@if (varianceOk) {
<p class="eod-verdict eod-verdict--ok">
<mat-icon>check_circle</mat-icon>
Your cash agrees. Nothing short, nothing over.
</p>
} @else {
<p class="eod-verdict eod-verdict--bad">
<mat-icon>error</mat-icon>
{{ variance! > 0 ? 'Extra' : 'Short' }} by
{{ (variance! > 0 ? variance : -variance!) | currency: 'INR' }}. Explain this before closing.
</p>
}
} @else {
<p class="eod-note">Today&rsquo;s cash legs were not sent for this login, so nothing is compared.</p>
}
} @else {
<p class="eod-caption">Cash that moved across the branch today</p>
<table class="pg-table eod-recon">
<tbody>
<tr>
<td>Cash taken from members <span class="eod-hint">deposits</span></td>
<td class="num col-in">+{{ branchDeposits ?? 0 | currency: 'INR' }}</td>
</tr>
<tr>
<td>Cash paid to members <span class="eod-hint">withdrawals and closures</span></td>
<td class="num col-out">−{{ branchWithdrawals ?? 0 | currency: 'INR' }}</td>
</tr>
<tr class="eod-recon__expected">
<td><strong>Net change today</strong></td>
<td class="num col-net">
<strong>{{ branchNetMovement | currency: 'INR' }}</strong>
</td>
</tr>
</tbody>
</table>
<p class="eod-caption eod-caption--spaced">Cash the branch is holding right now</p>
<table class="pg-table eod-recon">
<tbody>
<tr>
<td>In the vaults</td>
<td class="num">{{ vaultTotal ?? 0 | currency: 'INR' }}</td>
</tr>
<tr>
<td>With the cashiers</td>
<td class="num">{{ drawersTotal ?? 0 | currency: 'INR' }}</td>
</tr>
<tr class="eod-recon__expected">
<td><strong>Total cash in the branch</strong></td>
<td class="num">
@if (branchHeldTotal !== null) {
<strong>{{ branchHeldTotal | currency: 'INR' }}</strong>
} @else {
<span class="eod-blank">nothing recorded</span>
}
</td>
</tr>
</tbody>
</table>
<p class="eod-note">
These are two different things and are not subtracted from each other. The first is today&rsquo;s movement;
the second is everything the branch has accumulated to date. Each cashier&rsquo;s own drawer is checked
against their own day on their login, and the branch figure is signed off on the Day Open / Day Close
screen.
</p>
}
</section>
<!-- ── 3. Who handled the day, and what each drawer holds ──
A clerk signs off other people's work, so the sheet has to name them. On a cashier's own
login this collapses to one row, which is still the right thing to print. -->
<section class="eod-section">
<h3 class="eod-section__title"><span class="eod-section__no">3</span> Handled By</h3>
@if (byUser.length) {
<p class="eod-caption">What each person handled</p>
<table class="pg-table">
<thead>
<tr>
<th>Handled by</th>
<th class="num">Entries</th>
<th class="num col-in">Money in</th>
<th class="num col-out">Money out</th>
<th class="num col-net">Net</th>
</tr>
</thead>
<tbody>
@for (u of byUser; track u.label) {
<tr>
<td>{{ u.label }}</td>
<td class="num">{{ u.count }}</td>
<td class="num col-in">{{ u.credit ? (u.credit | currency: 'INR') : '—' }}</td>
<td class="num col-out">{{ u.debit ? (u.debit | currency: 'INR') : '—' }}</td>
<td class="num col-net">{{ u.credit - u.debit | currency: 'INR' }}</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td><strong>Total</strong></td>
<td class="num">
<strong>{{ txnCount }}</strong>
</td>
<td class="num col-in">
<strong>{{ summaryCreditTotal | currency: 'INR' }}</strong>
</td>
<td class="num col-out">
<strong>{{ summaryDebitTotal | currency: 'INR' }}</strong>
</td>
<td class="num col-net">
<strong>{{ summaryCreditTotal - summaryDebitTotal | currency: 'INR' }}</strong>
</td>
</tr>
</tfoot>
</table>
} @else {
<div class="pg-empty">Nobody moved money on this date.</div>
}
@if (cashierPositions.length) {
<p class="eod-caption eod-caption--spaced">What each cashier is holding</p>
<table class="pg-table">
<thead>
<tr>
<th>Cashier</th>
<th class="num">Cash held</th>
</tr>
</thead>
<tbody>
@for (p of cashierPositions; track p.cashierId) {
<tr>
<td>{{ p.cashierName }}</td>
<td class="num">{{ p.totalAmount | currency: 'INR' }}</td>
</tr>
}
</tbody>
@if (cashierPositions.length > 1) {
<tfoot>
<tr>
<td><strong>Total</strong></td>
<td class="num">
<strong>{{ cashierPositionTotal | currency: 'INR' }}</strong>
</td>
</tr>
</tfoot>
}
</table>
<p class="eod-note">
This is what each drawer should contain right now &mdash; a running total, not just today. Count against it
before settling to the vault.
</p>
}
</section>
<!-- ── 4. Every transaction ──
The sections above are totals, and a total nobody can break down is a total nobody can
check. This is the day itself, line by line, so a figure above can be traced to the
entries that made it. -->
<section class="eod-section eod-section--wide">
<h3 class="eod-section__title"><span class="eod-section__no">4</span> Every Transaction</h3>
@if (approvedRows.length) {
<table class="pg-table eod-txns">
<thead>
<tr>
<th>Voucher</th>
<th>Kind</th>
<th>Account</th>
<th>Party</th>
<th>Handled by</th>
<th class="num col-in">Money in</th>
<th class="num col-out">Money out</th>
</tr>
</thead>
<tbody>
@for (r of approvedRows; track r.voucherNo + '|' + r.txnId) {
<tr>
<td class="eod-mono">{{ r.voucherNo || '—' }}</td>
<td>{{ kindLabel(r.kind) }}</td>
<td class="eod-mono">{{ r.accountNo || '—' }}</td>
<td>{{ r.party || '—' }}</td>
<td>{{ r.handledBy || '—' }}</td>
<td class="num col-in">{{ r.side === 'CR' ? (r.amount | currency: 'INR') : '—' }}</td>
<td class="num col-out">{{ r.side === 'DR' ? (r.amount | currency: 'INR') : '—' }}</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<strong>Total &mdash; {{ txnCount }} entries</strong>
</td>
<td class="num col-in">
<strong>{{ summaryCreditTotal | currency: 'INR' }}</strong>
</td>
<td class="num col-out">
<strong>{{ summaryDebitTotal | currency: 'INR' }}</strong>
</td>
</tr>
</tfoot>
</table>
} @else {
<div class="pg-empty">No transactions on this date.</div>
}
@if (pendingRows.length) {
<p class="eod-caption eod-caption--spaced">Still pending &mdash; no money has moved on these</p>
<table class="pg-table eod-txns">
<thead>
<tr>
<th>Voucher</th>
<th>Kind</th>
<th>Account</th>
<th>Party</th>
<th>Raised by</th>
<th class="num">Amount</th>
</tr>
</thead>
<tbody>
@for (r of pendingRows; track r.voucherNo + '|' + r.txnId) {
<tr>
<td class="eod-mono">{{ r.voucherNo || '—' }}</td>
<td>{{ kindLabel(r.kind) }}</td>
<td class="eod-mono">{{ r.accountNo || '—' }}</td>
<td>{{ r.party || '—' }}</td>
<td>{{ r.handledBy || '—' }}</td>
<td class="num">{{ r.amount | currency: 'INR' }}</td>
</tr>
}
</tbody>
</table>
}
</section>
<!-- ── Last night's batch ──
Yesterday's work, posted after that day had already been counted and signed. Shown here
so it is not lost, kept out of every total above so today's figures still tie to the
ledger. Only appears when there is such a batch. -->
@if (priorDayRows.length) {
<section class="eod-section eod-section--wide eod-section--prior">
<h3 class="eod-section__title">
<mat-icon class="eod-section__icon">nights_stay</mat-icon>
Posted Overnight &mdash; work of
{{ priorDayDate ? (priorDayDate | date: 'dd MMM yyyy') : 'the previous day' }}
</h3>
<!-- Both dates side by side, because the whole point of this block is that they differ.
A reader who only sees one of them cannot tell whether the entry is being counted
today or merely reported today. -->
<div class="eod-datepair">
<div class="eod-datepair__item">
<span class="eod-datepair__label">These belong to</span>
<span class="eod-datepair__value">{{
priorDayDate ? (priorDayDate | date: 'dd MMM yyyy') : 'the previous day'
}}</span>
<span class="eod-datepair__hint">the day the system posted them against &mdash; already closed</span>
</div>
<div class="eod-datepair__arrow">→</div>
<div class="eod-datepair__item">
<span class="eod-datepair__label">Showing on</span>
<span class="eod-datepair__value">{{ date | date: 'dd MMM yyyy' }}</span>
<span class="eod-datepair__hint">today&rsquo;s report, because the run finished after midnight</span>
</div>
</div>
<p class="eod-note eod-note--lead">
The nightly run posted these after
{{ priorDayDate ? (priorDayDate | date: 'dd MMM') : 'the previous day' }} had already closed and been signed
off, so they surface on today&rsquo;s report instead. In the ledger they sit on
{{ priorDayDate ? (priorDayDate | date: 'dd MMM') : 'that date' }}, and they are
<strong>not counted</strong> in any figure above.
</p>
<table class="pg-table eod-txns">
<thead>
<tr>
<th>Voucher</th>
<th>Kind</th>
<th>Account</th>
<th>Party</th>
<th>Ledger date</th>
<th class="num col-in">Money in</th>
<th class="num col-out">Money out</th>
</tr>
</thead>
<tbody>
@for (r of priorDayRows; track r.voucherNo + '|' + r.txnId) {
<tr>
<td class="eod-mono">{{ r.voucherNo || '—' }}</td>
<td>{{ kindLabel(r.kind) }}</td>
<td class="eod-mono">{{ r.accountNo || '—' }}</td>
<td>{{ r.party || '—' }}</td>
<!-- Per row, not just in the heading: one run can span a date boundary, and a
reader checking a single figure against the ledger needs the date on the line
they are looking at. -->
<td class="eod-datecell">{{ r.effectiveDate ? (r.effectiveDate | date: 'dd MMM yyyy') : '—' }}</td>
<td class="num col-in">{{ r.side === 'CR' ? (r.amount | currency: 'INR') : '—' }}</td>
<td class="num col-out">{{ r.side === 'DR' ? (r.amount | currency: 'INR') : '—' }}</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<strong>Total &mdash; {{ priorDayRows.length }} entries</strong>
</td>
<td class="num col-in">
<strong>{{ priorDayCredit | currency: 'INR' }}</strong>
</td>
<td class="num col-out">
<strong>{{ priorDayDebit | currency: 'INR' }}</strong>
</td>
</tr>
</tfoot>
</table>
</section>
}
<!-- ── 5. Operational notes ── -->
<section class="eod-section">
<h3 class="eod-section__title"><span class="eod-section__no">5</span> Anything Outstanding</h3>
<ul class="eod-notes">
<li>
<span class="eod-notes__label">Entries handled</span>
<span class="eod-notes__value">{{ txnCount }} entries &middot; {{ kindLines.length }} kind(s)</span>
</li>
<li [class.eod-notes--warn]="pendingRows.length > 0">
<span class="eod-notes__label">Waiting for approval</span>
<span class="eod-notes__value">
@if (pendingRows.length) {
{{ pendingRows.length }} entry(ies) &mdash; the day cannot close until these are done
} @else {
None
}
</span>
</li>
<li [class.eod-notes--warn]="mismatchRows.length > 0">
<span class="eod-notes__label">Slips that did not match</span>
<span class="eod-notes__value">
@if (mismatchRows.length) {
{{ mismatchRows.length }} slip(s) do not agree with the system
} @else {
None
}
</span>
</li>
<li>
<span class="eod-notes__label">Slips not checked yet</span>
<span class="eod-notes__value">
{{
unverifiedRows.length
? unverifiedRows.length + ' entry(ies) still to be checked against paper'
: 'All checked'
}}
</span>
</li>
@if (priorDayRows.length) {
<li>
<span class="eod-notes__label">Posted overnight</span>
<span class="eod-notes__value">
{{ priorDayRows.length }} entry(ies) for
{{ priorDayDate ? (priorDayDate | date: 'dd MMM') : 'the previous day' }} &mdash; listed in their own
section, not in today&rsquo;s figures
</span>
</li>
}
<li [class.eod-notes--ok]="allClear">
<span class="eod-notes__label">Status</span>
<span class="eod-notes__value">
{{
allClear
? 'Everything is clear — the day is ready to close.'
: 'Sort out the items above before closing the day.'
}}
</span>
</li>
</ul>
</section>
<!-- ── Signatures ── -->
<section class="eod-sign">
<div class="eod-sign__block">
<div class="eod-sign__line"></div>
<div class="eod-sign__role">{{ supervising ? 'Prepared by' : 'Cashier' }}</div>
<div class="eod-sign__name">{{ preparedBy || '' }}</div>
</div>
<div class="eod-sign__block">
<div class="eod-sign__line"></div>
<div class="eod-sign__role">Manager / Principal Officer</div>
<div class="eod-sign__name">&nbsp;</div>
</div>
</section>
<p class="eod-foot">
Generated from the day book and the closing cash report for {{ date | date: 'dd MMM yyyy' }}. Figures move with
the underlying vouchers &mdash; reprint after any reversal.
</p>
</div>
}
</div>