- Savings/Current/FD/RD withdrawal forms: card-style overdraft warning when requested denomination count exceeds cashier stock; submit blocked on overdraft - Cash History detail view: show both RECEIVED and GIVEN denomination breakdowns for Cash Exchange (previously only RECEIVED side was displayed) - Closing Cash Report: add Cash Exchanges section (denomination-wise received/given/net) - Excess Transaction Report: include cash exchanges >= threshold with Type badge (Exchange/Txn) and ID Proof column for RBI/AML compliance - cashier-shared.scss: etr-badge and closing-exchange-head styles - Cash Exchange entry: overdraft warning redesigned to cx-overdraft-card BEM layout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
232 lines
8.5 KiB
HTML
232 lines
8.5 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="cx">
|
||
<header class="cx-head">
|
||
<div>
|
||
<div class="cx-eyebrow">CASHIER · CASH EXCHANGE</div>
|
||
<h1 class="cx-title">Cash Exchange Entry</h1>
|
||
<p class="cx-sub">Customer gives notes/coins and takes equal-value change. Net amount must be ₹0.</p>
|
||
</div>
|
||
<div class="cx-toolbar">
|
||
<label class="cx-field">
|
||
<span>Date</span>
|
||
<input type="date" [value]="exchangeDate" (change)="exchangeDate = $any($event.target).value" />
|
||
</label>
|
||
<button type="button" class="cx-btn cx-btn--ghost" (click)="clear()"><mat-icon>undo</mat-icon> Clear</button>
|
||
</div>
|
||
</header>
|
||
|
||
<!-- ── Customer Info Bar ── -->
|
||
<div class="cx-customer-bar">
|
||
<div
|
||
class="cx-customer-toggle"
|
||
[class.cx-customer-toggle--active]="isAccountHolder"
|
||
(click)="toggleAccountHolder()"
|
||
>
|
||
<mat-icon>{{ isAccountHolder ? 'check_box' : 'check_box_outline_blank' }}</mat-icon>
|
||
<span>Account Holder</span>
|
||
</div>
|
||
|
||
@if (isAccountHolder) {
|
||
<label class="cx-field cx-field--inline">
|
||
<span>Account No.</span>
|
||
<input
|
||
type="text"
|
||
[value]="accountNo"
|
||
(input)="accountNo = $any($event.target).value"
|
||
placeholder="e.g. 000101234567"
|
||
/>
|
||
</label>
|
||
} @else {
|
||
<span class="cx-walk-in"><mat-icon>person_outline</mat-icon> Walk-in Customer</span>
|
||
}
|
||
|
||
@if (needsIdProof) {
|
||
<div class="cx-pan-required">
|
||
<mat-icon>warning</mat-icon>
|
||
<span>Amount ≥ ₹50,000 — Customer PAN / Aadhaar required (RBI)</span>
|
||
</div>
|
||
<label class="cx-field cx-field--inline cx-field--pan">
|
||
<span>PAN / Aadhaar *</span>
|
||
<input
|
||
type="text"
|
||
[value]="customerIdProof"
|
||
(input)="customerIdProof = $any($event.target).value"
|
||
placeholder="ABCDE1234F"
|
||
maxlength="20"
|
||
/>
|
||
</label>
|
||
}
|
||
</div>
|
||
|
||
<div class="cx-cols">
|
||
<!-- RECEIVED -->
|
||
<section class="cx-col cx-col--received">
|
||
<header class="cx-col-head">
|
||
<mat-icon>south</mat-icon>
|
||
<span class="cx-col-title">Received from customer</span>
|
||
<span class="cx-col-total">₹{{ receivedTotal | number: '1.2-2' }}</span>
|
||
</header>
|
||
<div class="cx-list">
|
||
@if (notes.length) {
|
||
<div class="cx-subhead">Bank Notes</div>
|
||
}
|
||
@for (d of notes; track d.id) {
|
||
<div class="cx-row">
|
||
<span class="cx-chip">{{ d.label }}</span>
|
||
<div class="cx-step">
|
||
<button type="button" (click)="bump('r', d, -1)" [disabled]="countFor('r', d) === 0">−</button>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
[value]="countFor('r', d)"
|
||
(input)="onChange('r', d, $any($event.target).value)"
|
||
/>
|
||
<button type="button" (click)="bump('r', d, 1)">+</button>
|
||
</div>
|
||
<span class="cx-amt" [class.cx-amt--zero]="countFor('r', d) === 0"
|
||
>₹{{ subtotal('r', d) | number: '1.2-2' }}</span
|
||
>
|
||
</div>
|
||
}
|
||
@if (coins.length) {
|
||
<div class="cx-subhead">Coins</div>
|
||
}
|
||
@for (d of coins; track d.id) {
|
||
<div class="cx-row">
|
||
<span class="cx-chip cx-chip--coin">{{ d.label }}</span>
|
||
<div class="cx-step">
|
||
<button type="button" (click)="bump('r', d, -1)" [disabled]="countFor('r', d) === 0">−</button>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
[value]="countFor('r', d)"
|
||
(input)="onChange('r', d, $any($event.target).value)"
|
||
/>
|
||
<button type="button" (click)="bump('r', d, 1)">+</button>
|
||
</div>
|
||
<span class="cx-amt" [class.cx-amt--zero]="countFor('r', d) === 0"
|
||
>₹{{ subtotal('r', d) | number: '1.2-2' }}</span
|
||
>
|
||
</div>
|
||
}
|
||
</div>
|
||
</section>
|
||
|
||
<!-- GIVEN -->
|
||
<section class="cx-col cx-col--given">
|
||
<header class="cx-col-head">
|
||
<mat-icon>north</mat-icon>
|
||
<span class="cx-col-title">Given to customer</span>
|
||
<span class="cx-col-total">₹{{ givenTotal | number: '1.2-2' }}</span>
|
||
</header>
|
||
<div class="cx-list">
|
||
@if (notes.length) {
|
||
<div class="cx-subhead">Bank Notes</div>
|
||
}
|
||
@for (d of notes; track d.id) {
|
||
<div class="cx-row">
|
||
<span class="cx-chip">{{ d.label }}</span>
|
||
<div class="cx-step">
|
||
<button type="button" (click)="bump('g', d, -1)" [disabled]="countFor('g', d) === 0">−</button>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
[value]="countFor('g', d)"
|
||
(input)="onChange('g', d, $any($event.target).value)"
|
||
/>
|
||
<button type="button" (click)="bump('g', d, 1)">+</button>
|
||
</div>
|
||
<span class="cx-amt" [class.cx-amt--zero]="countFor('g', d) === 0"
|
||
>₹{{ subtotal('g', d) | number: '1.2-2' }}</span
|
||
>
|
||
</div>
|
||
}
|
||
@if (coins.length) {
|
||
<div class="cx-subhead">Coins</div>
|
||
}
|
||
@for (d of coins; track d.id) {
|
||
<div class="cx-row">
|
||
<span class="cx-chip cx-chip--coin">{{ d.label }}</span>
|
||
<div class="cx-step">
|
||
<button type="button" (click)="bump('g', d, -1)" [disabled]="countFor('g', d) === 0">−</button>
|
||
<input
|
||
type="number"
|
||
min="0"
|
||
[value]="countFor('g', d)"
|
||
(input)="onChange('g', d, $any($event.target).value)"
|
||
/>
|
||
<button type="button" (click)="bump('g', d, 1)">+</button>
|
||
</div>
|
||
<span class="cx-amt" [class.cx-amt--zero]="countFor('g', d) === 0"
|
||
>₹{{ subtotal('g', d) | number: '1.2-2' }}</span
|
||
>
|
||
</div>
|
||
}
|
||
</div>
|
||
</section>
|
||
</div>
|
||
|
||
<div class="cx-summary">
|
||
<div class="cx-sum">
|
||
<span>Received</span><strong>₹{{ receivedTotal | number: '1.2-2' }}</strong>
|
||
</div>
|
||
<mat-icon>swap_horiz</mat-icon>
|
||
<div class="cx-sum">
|
||
<span>Given</span><strong>₹{{ givenTotal | number: '1.2-2' }}</strong>
|
||
</div>
|
||
<div class="cx-sum">
|
||
<span>Difference</span>
|
||
<strong [class.cx-bad]="difference !== 0" [class.cx-good]="matches">₹{{ difference | number: '1.2-2' }}</strong>
|
||
</div>
|
||
</div>
|
||
|
||
@if (receivedTotal > 0 && !matches) {
|
||
<div class="cx-warn"><mat-icon>warning</mat-icon> Received and Given totals must match (net ₹0).</div>
|
||
}
|
||
@if (hasGivenOverdraft) {
|
||
<div class="cx-overdraft-card">
|
||
<div class="cx-overdraft-card__title">
|
||
<mat-icon class="cx-overdraft-card__ico">block</mat-icon>
|
||
<span>Insufficient stock — cannot give to customer</span>
|
||
</div>
|
||
<div class="cx-overdraft-card__rows">
|
||
@for (item of givenOverdraftItems; track item.label) {
|
||
<div class="cx-overdraft-card__row">
|
||
<span class="cx-overdraft-card__chip">{{ item.label }}</span>
|
||
<span class="cx-overdraft-card__stat"
|
||
><span class="cx-overdraft-card__lbl">Need</span><strong>{{ item.requested }}</strong></span
|
||
>
|
||
<span class="cx-overdraft-card__dot">·</span>
|
||
<span class="cx-overdraft-card__stat"
|
||
><span class="cx-overdraft-card__lbl">Available</span><strong>{{ item.available }}</strong></span
|
||
>
|
||
<span class="cx-overdraft-card__short">Short: {{ item.requested - item.available }}</span>
|
||
</div>
|
||
}
|
||
</div>
|
||
</div>
|
||
}
|
||
@if (needsIdProof && !customerIdProof.trim()) {
|
||
<div class="cx-warn cx-warn--pan">
|
||
<mat-icon>badge</mat-icon> Enter customer PAN / Aadhaar to proceed (amount ≥ ₹50,000).
|
||
</div>
|
||
}
|
||
|
||
<div class="cx-actions">
|
||
<label class="cx-field cx-field--note">
|
||
<span>Note</span>
|
||
<input type="text" [value]="note" (input)="note = $any($event.target).value" placeholder="Optional" />
|
||
</label>
|
||
<button type="button" class="cx-btn cx-btn--primary" [disabled]="!valid || saving" (click)="submit()">
|
||
<mat-icon>swap_horiz</mat-icon> {{ saving ? 'Saving…' : 'Confirm Exchange' }}
|
||
</button>
|
||
</div>
|
||
</div>
|