diff --git a/src/app/cashier/transaction-entry/transaction-entry.component.scss b/src/app/cashier/transaction-entry/transaction-entry.component.scss
index 90b526356..3a7a9ab39 100644
--- a/src/app/cashier/transaction-entry/transaction-entry.component.scss
+++ b/src/app/cashier/transaction-entry/transaction-entry.component.scss
@@ -620,7 +620,7 @@ $ws-fld-bd: #c8d8eb;
flex-shrink: 0;
&--type {
- width: 90px;
+ width: 160px;
}
&--branch {
@@ -636,13 +636,13 @@ $ws-fld-bd: #c8d8eb;
}
&--acno {
- flex: 1.6;
- min-width: 150px;
+ flex: 1;
+ min-width: 110px;
}
&--ecsno {
- flex: 1;
- min-width: 110px;
+ flex: 1.6;
+ min-width: 150px;
}
&--dbcr {
@@ -651,7 +651,7 @@ $ws-fld-bd: #c8d8eb;
}
&--paytype {
- width: 110px;
+ width: 160px;
}
&--amt {
@@ -659,7 +659,7 @@ $ws-fld-bd: #c8d8eb;
}
&--cheqno {
- width: 100px;
+ width: 165px;
}
&--cheqdt {
@@ -667,7 +667,7 @@ $ws-fld-bd: #c8d8eb;
}
&--tok {
- width: 72px;
+ width: 120px;
}
&--desc {
diff --git a/src/app/cashier/transaction-entry/transaction-entry.component.ts b/src/app/cashier/transaction-entry/transaction-entry.component.ts
index ca8cdba70..cca15d147 100644
--- a/src/app/cashier/transaction-entry/transaction-entry.component.ts
+++ b/src/app/cashier/transaction-entry/transaction-entry.component.ts
@@ -10,8 +10,8 @@ import { Component, OnInit, OnDestroy, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { HttpClient, HttpParams } from '@angular/common/http';
-import { catchError } from 'rxjs/operators';
-import { forkJoin, of } from 'rxjs';
+import { catchError, debounceTime, distinctUntilChanged } from 'rxjs/operators';
+import { forkJoin, of, Subject } from 'rxjs';
import { MatDialog, MatDialogModule, MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { CashierService } from '../cashier.service';
import { AuthenticationService } from '../../core/authentication/authentication.service';
@@ -659,6 +659,7 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
// Search token — cancels stale async results
private searchToken = 0;
+ private acNoInput$ = new Subject<{ row: TxnRow; index: number; value: string }>();
// Joint holder expanded details (keyed by index)
expandedHolder: number | null = null;
@@ -710,7 +711,8 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
'FD',
'RD',
'SHR',
- 'CC'
+ 'GL',
+ 'LA'
];
dbCrOptions = [
'Dr',
@@ -753,6 +755,18 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
.pipe(catchError(() => of([])))
.subscribe((types: any[]) => (this.paymentTypes = types ?? []));
+ this.acNoInput$
+ .pipe(
+ debounceTime(400),
+ distinctUntilChanged((a, b) => a.value === b.value && a.row === b.row)
+ )
+ .subscribe(({ row, index, value }) => {
+ if (value.trim().length >= 4) {
+ this.selectedRow = row;
+ this.loadAccountDetails(value.trim(), row.acTyp);
+ }
+ });
+
if (this.isClerk) {
const saved = this.clerkUiState.snapshot.savedAccount;
if (saved) {
@@ -1022,6 +1036,11 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
this.loadAccountDetails(row.acNo.trim(), row.acTyp);
}
+ onAcNoInput(row: TxnRow, index: number, value: string): void {
+ row.acNo = value;
+ this.acNoInput$.next({ row, index, value });
+ }
+
onRowSelect(row: TxnRow, index: number): void {
this.selectedRow = row;
// Only reload if account number changed or nothing is loaded yet
@@ -1055,32 +1074,24 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
// Step 1: search by accountNo on the correct endpoint for this account type
this.http
- .get
(`${cfg.list}?accountNo=${encodeURIComponent(acNo)}&offset=0&limit=1`)
+ .get(`${cfg.list}?accountNo=${encodeURIComponent(acNo)}&offset=0&limit=${cfg.maxLimit}`)
.pipe(catchError(() => of(null)))
.subscribe((res: any) => {
if (token !== this.searchToken) return; // stale result — newer search started
const allItems: any[] = res?.pageItems ?? (Array.isArray(res) ? res : []);
- // Find exact match by accountNo — prevents taking wrong first item when API
- // returns all accounts as an array (e.g. recurringdepositaccounts)
- const match = allItems.find((x: any) => x.accountNo === acNo) ?? allItems[0];
+ // Exact match first, then suffix/partial match (backend may return by last-N-digits)
+ const exactMatch = allItems.find((x: any) => x.accountNo === acNo);
+ const partialMatch =
+ !exactMatch && allItems.length === 1
+ ? allItems.find((x: any) => x.accountNo?.endsWith(acNo) || x.accountNo?.includes(acNo))
+ : null;
+ const match = exactMatch ?? partialMatch ?? null;
if (match?.id) {
- this.fetchAllDetails(match.id, acNo, cfg, token, acTyp);
+ this.fetchAllDetails(match.id, match.accountNo, cfg, token, acTyp);
return;
}
- // Fallback: global search
- this.http
- .get(`/search?query=${encodeURIComponent(acNo)}&resource=${cfg.search}`)
- .pipe(catchError(() => of([])))
- .subscribe((found: any) => {
- if (token !== this.searchToken) return;
- const list: any[] = Array.isArray(found) ? found : [];
- if (list.length > 0 && list[0].entityId) {
- this.fetchAllDetails(list[0].entityId, acNo, cfg, token, acTyp);
- } else {
- this.loadingAccount = false;
- this.accountError = 'Account not found for: ' + acNo;
- }
- });
+ this.loadingAccount = false;
+ this.accountError = 'Account not found for: ' + acNo;
});
}
@@ -1093,10 +1104,52 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
siAccountType: number;
txnBase: string;
txnSearchSupported: boolean;
+ maxLimit: number;
+ skipGlobalSearch: boolean;
} {
const t = acTyp?.toUpperCase();
- if (t === 'CA' || t === 'CB' || t === 'CC') {
- // Current account: custom /transactions/search endpoint added to backend
+ if (t === 'LA') {
+ return {
+ list: '/loans',
+ detail: '/loans',
+ nominee: 'LA',
+ search: 'loan',
+ siAccountType: 1,
+ txnBase: '/loans',
+ txnSearchSupported: true,
+ maxLimit: 1,
+ skipGlobalSearch: true
+ };
+ }
+ if (t === 'SHR') {
+ // Backend ignores accountNo filter on list — fetch all and match client-side
+ // Global /search?resource=share returns 500 — skip it
+ return {
+ list: '/accounts/share',
+ detail: '/accounts/share',
+ nominee: 'SHR',
+ search: 'share',
+ siAccountType: 4,
+ txnBase: '/accounts/share',
+ txnSearchSupported: false,
+ maxLimit: 500,
+ skipGlobalSearch: true
+ };
+ }
+ if (t === 'GL') {
+ return {
+ list: '/glaccounts',
+ detail: '/glaccounts',
+ nominee: 'GL',
+ search: 'glaccount',
+ siAccountType: 0,
+ txnBase: '/glaccounts',
+ txnSearchSupported: false,
+ maxLimit: 500,
+ skipGlobalSearch: true
+ };
+ }
+ if (t === 'CA' || t === 'CB') {
return {
list: '/currentaccounts',
detail: '/currentaccounts',
@@ -1104,11 +1157,12 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
search: 'currentaccount',
siAccountType: 3,
txnBase: '/currentaccounts',
- txnSearchSupported: true
+ txnSearchSupported: true,
+ maxLimit: 1,
+ skipGlobalSearch: true
};
}
if (t === 'FD') {
- // FD stored in savings table → use /savingsaccounts for transaction search
return {
list: '/savingsaccounts',
detail: '/fixeddepositaccounts',
@@ -1116,11 +1170,12 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
search: 'fixeddeposit',
siAccountType: 2,
txnBase: '/savingsaccounts',
- txnSearchSupported: true
+ txnSearchSupported: true,
+ maxLimit: 1,
+ skipGlobalSearch: true
};
}
if (t === 'RD') {
- // RD stored in savings table → use /savingsaccounts for transaction search
return {
list: '/savingsaccounts',
detail: '/recurringdepositaccounts',
@@ -1128,10 +1183,12 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
search: 'recurringdeposit',
siAccountType: 2,
txnBase: '/savingsaccounts',
- txnSearchSupported: true
+ txnSearchSupported: true,
+ maxLimit: 1,
+ skipGlobalSearch: true
};
}
- // SD — savings with full search support
+ // SD — savings
return {
list: '/savingsaccounts',
detail: '/savingsaccounts',
@@ -1139,7 +1196,9 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
search: 'saving',
siAccountType: 2,
txnBase: '/savingsaccounts',
- txnSearchSupported: true
+ txnSearchSupported: true,
+ maxLimit: 1,
+ skipGlobalSearch: true
};
}
@@ -1182,6 +1241,10 @@ export class TransactionEntryComponent implements OnInit, OnDestroy {
}
this.accountDetails = acc;
this.jointHolders = acc.jointHolders ?? [];
+ // Auto-fill ECS A/C NO. with savings account number (SHR) or account number
+ if (this.selectedRow) {
+ this.selectedRow.ecsAcNo = acc.savingsAccountNumber ?? acc.accountNo ?? '';
+ }
if (this.isClerk) this.clerkUiState.setFacilities(this.facilities, acNo, acTyp);
// Compute same-day compliance indicators from included transactions
this.computeSameDayNeftRtgs(acc.transactions);