Files
cbsnexora/src/app/cashier/cash-exchange-entry/cash-exchange-entry.component.html
T
Jaanu423andClaude Sonnet 4.6 f291e4da5b feat(cashier): denomination overdraft validation, exchange detail fix, cash exchange in reports
- 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>
2026-06-01 10:10:17 +05:30

232 lines
8.5 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="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>