feat(cashier): enhance transaction entry TYPE/TXN TP options, auto-search, and account type configs

- Replace TYPE dropdown options with Withdrawal Slip, Cheque, Disbursement, Enter Bank Transfer, DD
- Move TXN TP. (payment type) into Classification row between BRANCH and AC. TP.
- Add GL and LA account types; fix SHR endpoint to /accounts/share
- Auto-search A/C NO. on 4+ digits with 400ms debounce
- Auto-fill ECS A/C NO. from savingsAccountNumber after account load
- Accept suffix/partial accountNo match from list API
- Disable broken global /search fallback across all account types
- Increase field widths: TYPE 160px, TXN TP. 160px, CHEQUE NO. 165px, TOK. NO. 120px

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Jaanu423
2026-06-09 18:26:20 +05:30
co-authored by Claude Sonnet 4.6
parent 40a436dabe
commit 010adcb44f
6 changed files with 462 additions and 89 deletions
@@ -21,6 +21,13 @@ import { CashierService } from '../cashier.service';
type PageState = 'idle' | 'searching' | 'loaded' | 'submitting' | 'success';
interface Denomination {
id: number;
value: number;
kind: 'note' | 'coin';
label: string;
}
interface ShareCharge {
id: number;
name: string;
@@ -68,6 +75,11 @@ export class ShareCollectionComponent implements OnInit {
requestedSharesInput = 0;
pricePerShare = 0;
// ── Denomination ────────────────────────────────────────────────────────────
notes: Denomination[] = [];
coins: Denomination[] = [];
denominationCounts: Record<string, number> = {};
get shareAmount(): number {
return this.requestedSharesInput * this.pricePerShare;
}
@@ -84,8 +96,34 @@ export class ShareCollectionComponent implements OnInit {
return this.account?.currency?.displaySymbol ?? '₹';
}
get isCashPayment(): boolean {
if (this.paymentTypeId === null) return true;
const pt = this.paymentTypes.find((p: any) => p.id === this.paymentTypeId);
return !!pt?.isCashPayment;
}
get allDenominations(): Denomination[] {
const desc = (a: Denomination, b: Denomination) => b.value - a.value;
return [
...[...this.notes].sort(desc),
...[...this.coins].sort(desc)
];
}
get denominationTotal(): number {
return this.allDenominations.reduce((s, d) => s + this.subtotalFor(d), 0);
}
get denomMatchesTotal(): boolean {
return this.denominationTotal === this.totalAmount;
}
get isValid(): boolean {
return !!this.account && this.totalAmount > 0 && !!this.transactionDate;
if (!this.account || this.totalAmount <= 0 || !this.transactionDate) return false;
if (this.isCashPayment && this.allDenominations.length > 0) {
return this.denomMatchesTotal;
}
return true;
}
ngOnInit(): void {
@@ -95,6 +133,50 @@ export class ShareCollectionComponent implements OnInit {
.getPaymentTypes()
.pipe(catchError(() => of([])))
.subscribe((types: any[]) => (this.paymentTypes = types || []));
this.loadDenominations();
}
private loadDenominations(): void {
this.service
.getActiveDenominations()
.pipe(catchError(() => of([])))
.subscribe((list: any[]) => {
const rows: Denomination[] = (list || []).map((d: any) => ({
id: d.id,
value: d.denomination ?? d.value,
kind: d.type === 'coin' ? 'coin' : 'note',
label: '₹' + (d.denomination ?? d.value)
}));
const order = (a: Denomination, b: Denomination) => b.value - a.value;
this.notes = rows.filter((r) => r.kind === 'note').sort(order);
this.coins = rows.filter((r) => r.kind === 'coin').sort(order);
});
}
// ── Denomination helpers ──────────────────────────────────────────────────
denomKey(d: Denomination): string {
return `${d.kind}:${d.value}`;
}
countFor(d: Denomination): number {
return this.denominationCounts[this.denomKey(d)] || 0;
}
subtotalFor(d: Denomination): number {
return this.countFor(d) * d.value;
}
onDenomChange(d: Denomination, raw: any): void {
this.denominationCounts[this.denomKey(d)] = Math.max(0, Math.floor(Number(raw) || 0));
}
bumpDenom(d: Denomination, delta: number): void {
this.denominationCounts[this.denomKey(d)] = Math.max(0, this.countFor(d) + delta);
}
clearDenominations(): void {
this.denominationCounts = {};
}
searchAccount(): void {
@@ -195,5 +277,6 @@ export class ShareCollectionComponent implements OnInit {
this.pricePerShare = 0;
this.collectionResult = null;
this.saving = false;
this.clearDenominations();
}
}