OVERVIEW
--------
Added real-time cashier cash position display inside the denomination breakdown
panel of all 4 transaction entry screens: Savings, Current Account, Recurring
Deposit, and Fixed Deposit. Shows opening balance at the top and projected
closing balance at the bottom after factoring in the current transaction.
BACKEND INTEGRATION
-------------------
- New CashierService (src/app/cashier/cashier.service.ts)
getCashierPositionForMe(asOfDate?) calls GET /cashreports/cashier-position/me
Returns denomination-wise opening cash position for the logged-in cashier user.
Non-cashier users receive empty denominations array; UI hides panels silently.
OPENING BALANCE CARD (top of denomination panel)
-------------------------------------------------
- Loaded on ngOnInit() via loadOpeningPosition() in all 4 component .ts files
- Notes and Coins displayed in separate labeled pill sections
- Each pill shows: Rs{value} x{count} format
- Card is hidden entirely if the logged-in user is not a cashier
CLOSING BALANCE CARD (below tally / Apply button)
--------------------------------------------------
- Computed getter closingDenoms() merges opening position with entered denominations
deposit: closingCount = openCount + enteredCount
withdrawal: closingCount = openCount - enteredCount
- Notes and Coins in separate labeled pill sections (identical format to opening)
- Entered/changed denominations (delta != 0): full opacity + bold font weight
- Untouched denominations (delta = 0): 38% opacity, clearly dimmed, no borders
- closingTotal = openingTotal +/- denominationTotal shown in card header
- Card turns green for positive closing balance, red for negative
COMPONENTS UPDATED
------------------
- savings-account-transactions (.ts / .html / .scss)
- current-account-transactions (.ts / .html / .scss)
- deposit-recurring-deposits-account (.ts / .html / .scss)
- fixed-deposits-cash-transaction (.ts / .html / .scss)
CASHIER MODULE (new - src/app/cashier/)
-----------------------------------------
Full cashier workspace module added to the app:
- cashier.service.ts API calls (position, transfers, settlement, etc.)
- cashier.module.ts Angular module declaration
- cashier-routing.module.ts Lazy-loaded routes
- cashier-position/ Cashier cash position dashboard
- cash-exchange-entry/ Cash exchange denomination entry
- cash-history/ Transaction history per cashier
- cash-settlement/ End-of-day cash settlement
- cash-transfer/ Vault-to-cashier cash transfer
- inter-cashier-transfer/ Transfer between cashier drawers
- reconciliation/ Cash reconciliation with GL
- closing-cash-report/ Closing balance report
- currency-exchange-detail/ Currency exchange breakdown
- excess-transaction-report/ Excess/short transaction report
Module wired into app.module.ts and shell nav (shell.component.html).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
124 lines
4.2 KiB
HTML
124 lines
4.2 KiB
HTML
<!--
|
||
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">
|
||
<header class="pg-head">
|
||
<div>
|
||
<div class="pg-eyebrow">CASHIER · POSITION REPORT</div>
|
||
<h1 class="pg-title">Cashier Position</h1>
|
||
<p class="pg-sub">
|
||
Denomination-wise net cash held by a cashier as of a date (allocations − settlements − inter-cashier transfers).
|
||
</p>
|
||
</div>
|
||
</header>
|
||
|
||
<div class="pg-toolbar pg-toolbar--mat">
|
||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||
<mat-label>Teller (optional)</mat-label>
|
||
<mat-select [value]="selectedTellerId" (selectionChange)="onTellerSelect($event.value)">
|
||
<mat-option [value]="null">All Tellers</mat-option>
|
||
@for (t of tellers; track t.id) {
|
||
<mat-option [value]="t.id">{{ t.name }}</mat-option>
|
||
}
|
||
</mat-select>
|
||
</mat-form-field>
|
||
|
||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||
<mat-label>Cashier (optional)</mat-label>
|
||
<mat-select [value]="selectedCashierId" (selectionChange)="selectedCashierId = $event.value">
|
||
<mat-option [value]="null">All Cashiers</mat-option>
|
||
@for (c of cashiers; track c.id) {
|
||
<mat-option [value]="c.id">{{ c.label }}</mat-option>
|
||
}
|
||
</mat-select>
|
||
</mat-form-field>
|
||
|
||
<mat-form-field appearance="outline" subscriptSizing="dynamic">
|
||
<mat-label>As of Date</mat-label>
|
||
<input matInput type="date" [value]="asOfDate" (change)="asOfDate = $any($event.target).value" />
|
||
</mat-form-field>
|
||
|
||
<button type="button" class="pg-btn pg-btn--primary" (click)="load()" [disabled]="loading">
|
||
<mat-icon>bar_chart</mat-icon> Load Position
|
||
</button>
|
||
</div>
|
||
|
||
@if (errorMsg) {
|
||
<div class="pg-empty" style="color: #dc2626">{{ errorMsg }}</div>
|
||
}
|
||
|
||
@if (loading) {
|
||
<div class="pg-empty">Loading…</div>
|
||
}
|
||
|
||
@for (pos of results; track pos.cashierId) {
|
||
<div class="pg-card" style="margin-bottom: 0">
|
||
<div class="pos-header">
|
||
<span class="pos-cashier">{{ pos.cashierName || labelForCashier(pos.cashierId) }}</span>
|
||
<span class="pos-total">₹{{ pos.totalAmount | number: '1.2-2' }}</span>
|
||
</div>
|
||
|
||
@if (pos.denominations.length === 0) {
|
||
<div class="pg-empty">No balance.</div>
|
||
}
|
||
|
||
@if (notes(pos).length > 0) {
|
||
<div class="pos-section-label">Notes</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th style="text-align: center">Count</th>
|
||
<th class="num">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (d of notes(pos); track d.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip">₹{{ d.denominationValue }}</span>
|
||
</td>
|
||
<td style="text-align: center; font-weight: 700">{{ d.count }}</td>
|
||
<td class="num">₹{{ d.amount | number: '1.2-2' }}</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
|
||
@if (coins(pos).length > 0) {
|
||
<div class="pos-section-label pos-section-label--coin">Coins</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th style="text-align: center">Count</th>
|
||
<th class="num">Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (d of coins(pos); track d.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip pg-chip--coin">₹{{ d.denominationValue }}</span>
|
||
</td>
|
||
<td style="text-align: center; font-weight: 700">{{ d.count }}</td>
|
||
<td class="num">₹{{ d.amount | number: '1.2-2' }}</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
</div>
|
||
}
|
||
|
||
@if (!loading && results.length === 0 && !errorMsg) {
|
||
<div class="pg-empty">Select filters and click "Load Position".</div>
|
||
}
|
||
</div>
|