feat: cash-only registers, day book sections and DD amendments
This commit is contained in:
@@ -27,12 +27,23 @@
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@if (!showGl && rows.length > 0) {
|
||||
<!-- Shown whenever the day has any cash at all, not only when a denomination breakdown exists:
|
||||
a cash Demand Draft is recorded without one, and gating on rows hid its money entirely. -->
|
||||
@if (!showGl && (rows.length > 0 || ddCashTotal > 0)) {
|
||||
<!-- Summary totals bar -->
|
||||
<div class="closing-summary">
|
||||
<div class="closing-summary__item closing-summary__item--in">
|
||||
<span class="closing-summary__label">Total Deposits (IN)</span>
|
||||
<span class="closing-summary__value">₹{{ depositTotal | number: '1.2-2' }}</span>
|
||||
<span class="closing-summary__value">₹{{ depositTotalWithDd | number: '1.2-2' }}</span>
|
||||
@if (ddCashTotal > 0) {
|
||||
<!-- Named on the tile as well as in the table: this part of the total carries no
|
||||
denomination, so without saying so the figures read as failing to add up. -->
|
||||
<span class="closing-summary__note">
|
||||
incl. ₹{{ ddCashTotal | number: '1.2-2' }} not itemised ({{ ddCashCount }} cash DD{{
|
||||
ddCashCount === 1 ? '' : 's'
|
||||
}})
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<div class="closing-summary__sep">−</div>
|
||||
<div class="closing-summary__item closing-summary__item--out">
|
||||
@@ -45,15 +56,57 @@
|
||||
[class.closing-summary__item--net-pos]="netTotal >= 0"
|
||||
[class.closing-summary__item--net-neg]="netTotal < 0"
|
||||
>
|
||||
<span class="closing-summary__label">Net Closing Cash</span>
|
||||
<!-- Named for what it is: the counter's own movement. It was labelled "Net Closing Cash",
|
||||
which it is not -- it carries nothing forward from yesterday and leaves out vault and
|
||||
inter-cashier legs, so it can differ from the drawer by a large amount. The real
|
||||
closing figure is in the balance strip below. -->
|
||||
<span class="closing-summary__label">Net Counter Movement</span>
|
||||
<span class="closing-summary__value">₹{{ netTotal | number: '1.2-2' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Opening → closing, the figure a physical count is checked against. Shown only for a
|
||||
cashier-scoped report; a branch-wide one has no single drawer to open and close. -->
|
||||
@if (!showGl && scopedToCashier && closingBalance !== null) {
|
||||
<div class="closing-summary closing-summary--balance">
|
||||
<div class="closing-summary__item">
|
||||
<span class="closing-summary__label">Opening Balance</span>
|
||||
<span class="closing-summary__value">₹{{ openingBalance | number: '1.2-2' }}</span>
|
||||
</div>
|
||||
<div class="closing-summary__sep">+</div>
|
||||
<div
|
||||
class="closing-summary__item"
|
||||
[class.closing-summary__item--in]="(cashMovement ?? 0) >= 0"
|
||||
[class.closing-summary__item--out]="(cashMovement ?? 0) < 0"
|
||||
>
|
||||
<span class="closing-summary__label">Cash Movement</span>
|
||||
<span class="closing-summary__value">₹{{ cashMovement | number: '1.2-2' }}</span>
|
||||
</div>
|
||||
<div class="closing-summary__sep">=</div>
|
||||
<div
|
||||
class="closing-summary__item"
|
||||
[class.closing-summary__item--net-pos]="(closingBalance ?? 0) >= 0"
|
||||
[class.closing-summary__item--net-neg]="(closingBalance ?? 0) < 0"
|
||||
>
|
||||
<span class="closing-summary__label">Closing Balance</span>
|
||||
<span class="closing-summary__value">₹{{ closingBalance | number: '1.2-2' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@if (cashMovement !== null && netTotal !== cashMovement) {
|
||||
<!-- The gap between the two is not an error: it is the vault, inter-cashier and exchange
|
||||
traffic that never crossed the counter. Said plainly, because two different "net"
|
||||
figures on one screen otherwise read as a bug. -->
|
||||
<p class="closing-note">
|
||||
Cash movement differs from counter movement by ₹{{ cashMovement - netTotal | number: '1.2-2' }} — vault,
|
||||
inter-cashier and exchange legs that did not pass over the counter.
|
||||
</p>
|
||||
}
|
||||
}
|
||||
|
||||
@if (!showGl) {
|
||||
<div class="pg-card">
|
||||
@if (noteRows.length > 0) {
|
||||
@if (noteRows.length > 0 || ddCashTotal > 0) {
|
||||
<div class="pos-section-label">Notes</div>
|
||||
<table class="pg-table">
|
||||
<thead>
|
||||
@@ -93,7 +146,42 @@
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
|
||||
<!-- Cash taken for a Demand Draft, on the deposit side where it belongs. It has no
|
||||
denomination to sit against -- the notes were never itemised -- so the piece
|
||||
counts show a dash rather than a zero, which would read as "no notes". -->
|
||||
@if (ddCashTotal > 0) {
|
||||
<tr>
|
||||
<td>
|
||||
<span class="pg-chip">Not itemised</span>
|
||||
<span class="closing-row__hint"> {{ ddCashCount }} cash DD{{ ddCashCount === 1 ? '' : 's' }} </span>
|
||||
</td>
|
||||
<td class="num col-in">—</td>
|
||||
<td class="num col-in">₹{{ ddCashTotal | number: '1.2-2' }}</td>
|
||||
<td class="num col-out">—</td>
|
||||
<td class="num col-out">₹0.00</td>
|
||||
<td class="num col-net">—</td>
|
||||
<td class="num col-net" style="color: #16a34a">+₹{{ ddCashTotal | number: '1.2-2' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
<!-- Totals, so the table reconciles against the summary above rather than having to be
|
||||
added up by hand — and so the deposit column visibly accounts for the DD row. -->
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td>Total</td>
|
||||
<td class="num col-in">{{ noteDepositCount }}</td>
|
||||
<td class="num col-in">₹{{ noteDepositAmount | number: '1.2-2' }}</td>
|
||||
<td class="num col-out">{{ noteWithdrawalCount }}</td>
|
||||
<td class="num col-out">₹{{ noteWithdrawalAmount | number: '1.2-2' }}</td>
|
||||
<td class="num col-net"></td>
|
||||
<td class="num col-net">
|
||||
{{ noteNetAmount >= 0 ? '+' : '−' }}₹{{
|
||||
(noteNetAmount < 0 ? -noteNetAmount : noteNetAmount) | number: '1.2-2'
|
||||
}}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
}
|
||||
|
||||
@@ -141,8 +229,20 @@
|
||||
</table>
|
||||
}
|
||||
|
||||
@if (loaded && rows.length === 0 && exchangeRows.length === 0) {
|
||||
<div class="pg-empty">No cash denomination data for this date.</div>
|
||||
<!-- Not shown when a Demand Draft row is on the table: there is something to read then, and
|
||||
an "empty" notice under it contradicts it. -->
|
||||
@if (loaded && rows.length === 0 && exchangeRows.length === 0 && ddCashTotal === 0) {
|
||||
<!-- A day with no counter work is not an empty report: the cashier is still holding
|
||||
whatever they held yesterday, and that balance is shown in the strip above. Saying
|
||||
only "no data" here read as though the drawer were empty. -->
|
||||
<div class="pg-empty">
|
||||
@if (scopedToCashier && closingBalance !== null) {
|
||||
No cash crossed the counter on this date. The drawer still holds ₹{{ closingBalance | number: '1.2-2' }},
|
||||
carried forward.
|
||||
} @else {
|
||||
No cash denomination data for this date.
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -38,6 +38,38 @@ export class ClosingCashReportComponent implements OnInit {
|
||||
loading = false;
|
||||
loaded = false;
|
||||
|
||||
/**
|
||||
* Cash taken at the counter for a Demand Draft.
|
||||
*
|
||||
* A cash DD asks for a denomination breakdown but does not require one, and this report is built
|
||||
* entirely from breakdowns — so that cash was missing from the drawer figure even though the
|
||||
* ledger held it and the cashier held the notes. It is counted from the request itself and shown
|
||||
* on its own line, because the denomination rows below cannot account for it.
|
||||
*/
|
||||
ddCashTotal = 0;
|
||||
ddCashCount = 0;
|
||||
/** Deposits including the DD cash — the figure the drawer is actually checked against. */
|
||||
depositTotalWithDd = 0;
|
||||
|
||||
/**
|
||||
* The drawer, opening to closing.
|
||||
*
|
||||
* `netTotal` above is only the day's counter movement — deposits less withdrawals. It is not what
|
||||
* the cashier is holding, because it carries nothing forward from yesterday and ignores vault
|
||||
* allocations and inter-cashier legs. The closing balance is the figure that has to match a
|
||||
* physical count at the end of the day, so it is reported separately rather than inferred from
|
||||
* the counter totals.
|
||||
*
|
||||
* Null when the server did not scope the report to one cashier: a branch-wide opening balance is
|
||||
* the branch day register's business, not this report's.
|
||||
*/
|
||||
openingBalance: number | null = null;
|
||||
closingBalance: number | null = null;
|
||||
/** Every leg of the day's cash movement, which is wider than deposits less withdrawals. */
|
||||
cashMovement: number | null = null;
|
||||
/** Whether the figures above are one cashier's drawer or the whole branch's counter work. */
|
||||
scopedToCashier = false;
|
||||
|
||||
// GL View
|
||||
showGl = false;
|
||||
glRows: any[] = [];
|
||||
@@ -66,6 +98,33 @@ export class ClosingCashReportComponent implements OnInit {
|
||||
get noteRows(): any[] {
|
||||
return this.rows.filter((r) => r.kind !== 'coin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Totals for the notes table, including the un-itemised Demand Draft cash.
|
||||
*
|
||||
* The DD row carries an amount but no piece count, so pieces and amounts are summed separately
|
||||
* rather than one being derived from the other — a denomination times a count would not reach the
|
||||
* DD's figure, and adding a fictional count to make it balance would misstate the drawer.
|
||||
*/
|
||||
get noteDepositCount(): number {
|
||||
return this.noteRows.reduce((s, r) => s + Number(r.depositCount ?? 0), 0);
|
||||
}
|
||||
|
||||
get noteDepositAmount(): number {
|
||||
return this.noteRows.reduce((s, r) => s + Number(r.depositAmount ?? 0), 0) + this.ddCashTotal;
|
||||
}
|
||||
|
||||
get noteWithdrawalCount(): number {
|
||||
return this.noteRows.reduce((s, r) => s + Number(r.withdrawalCount ?? 0), 0);
|
||||
}
|
||||
|
||||
get noteWithdrawalAmount(): number {
|
||||
return this.noteRows.reduce((s, r) => s + Number(r.withdrawalAmount ?? 0), 0);
|
||||
}
|
||||
|
||||
get noteNetAmount(): number {
|
||||
return this.noteDepositAmount - this.noteWithdrawalAmount;
|
||||
}
|
||||
get coinRows(): any[] {
|
||||
return this.rows.filter((r) => r.kind === 'coin');
|
||||
}
|
||||
@@ -92,6 +151,15 @@ export class ClosingCashReportComponent implements OnInit {
|
||||
this.depositTotal = Number(res?.depositTotal || 0);
|
||||
this.withdrawalTotal = Number(res?.withdrawalTotal || 0);
|
||||
this.netTotal = Number(res?.netTotal || 0);
|
||||
this.ddCashTotal = Number(res?.ddCashTotal || 0);
|
||||
this.ddCashCount = Number(res?.ddCashCount || 0);
|
||||
this.depositTotalWithDd = Number(res?.depositTotalWithDd ?? res?.depositTotal ?? 0);
|
||||
this.scopedToCashier = res?.scopedToCashier === true;
|
||||
// Sent only for a cashier-scoped call, and read as absent rather than zero when missing —
|
||||
// a zero opening balance and no opening balance at all are different statements.
|
||||
this.openingBalance = res?.openingBalance == null ? null : Number(res.openingBalance);
|
||||
this.closingBalance = res?.closingBalance == null ? null : Number(res.closingBalance);
|
||||
this.cashMovement = res?.cashMovement == null ? null : Number(res.cashMovement);
|
||||
this.loading = false;
|
||||
this.loaded = true;
|
||||
},
|
||||
@@ -101,6 +169,13 @@ export class ClosingCashReportComponent implements OnInit {
|
||||
this.depositTotal = 0;
|
||||
this.withdrawalTotal = 0;
|
||||
this.netTotal = 0;
|
||||
this.ddCashTotal = 0;
|
||||
this.ddCashCount = 0;
|
||||
this.depositTotalWithDd = 0;
|
||||
this.scopedToCashier = false;
|
||||
this.openingBalance = null;
|
||||
this.closingBalance = null;
|
||||
this.cashMovement = null;
|
||||
this.loading = false;
|
||||
this.loaded = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user