fix(cashier): realistic branch-aware account numbers, dynamic date tags in summary report
Account No now always holds a genuine reference for its transaction type (customer account, GL/facility code, IFSC, DD/PO/TDS/GST/cheque ref, or UTR/RRN/UMRN for RTGS/NEFT/UPI/ATM/NACH) instead of a plain description. Branch 2's view derives its own valid-format account numbers and IFSC codes by shifting the numeric segment, rather than tagging a "BR2-" prefix onto Branch 1's values, which looked fake for standardized formats. Voucher/reference numbers' baked-in "2607" (Jul 2026) tag is now derived from the real current date at render time, so it won't go stale next month. feat(clients): auto-calculate Monthly/Annual Income and Turnover Typing either the monthly or annual figure now fills in the other at a 12x ratio (rounded to 2 decimals, no trailing ".00" on whole numbers). Guarded against firing during prefillForEdit()'s initial load of an existing client's independently-saved values, so editing doesn't silently overwrite historical data that wasn't an exact 12x match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
+7
-8
@@ -219,7 +219,8 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Date</th>
|
<th>Date</th>
|
||||||
<th>Voucher / Ref No</th>
|
<th>Voucher / Ref No</th>
|
||||||
<th>Account / Reference</th>
|
<th>Account No</th>
|
||||||
|
<th>Account Name / Reference</th>
|
||||||
<th>Particulars</th>
|
<th>Particulars</th>
|
||||||
<th class="num col-out">Debit</th>
|
<th class="num col-out">Debit</th>
|
||||||
<th class="num col-in">Credit</th>
|
<th class="num col-in">Credit</th>
|
||||||
@@ -230,12 +231,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ asOnDate }}</td>
|
<td>{{ asOnDate }}</td>
|
||||||
<td>
|
<td>
|
||||||
<span class="pg-chip">{{ t.voucherNo }}</span>
|
<span class="pg-chip">{{ display(t.voucherNo) }}</span>
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<div>{{ t.accountName }}</div>
|
|
||||||
<div class="cctr-subtext">{{ t.accountNo }}</div>
|
|
||||||
</td>
|
</td>
|
||||||
|
<td>{{ display(t.accountNo) }}</td>
|
||||||
|
<td>{{ t.accountName }}</td>
|
||||||
<td>{{ t.particulars }}</td>
|
<td>{{ t.particulars }}</td>
|
||||||
<td class="num col-out">
|
<td class="num col-out">
|
||||||
@if (t.debit > 0) {
|
@if (t.debit > 0) {
|
||||||
@@ -250,13 +249,13 @@
|
|||||||
</tr>
|
</tr>
|
||||||
} @empty {
|
} @empty {
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="6" class="pg-empty">No transactions for this filter.</td>
|
<td colspan="7" class="pg-empty">No transactions for this filter.</td>
|
||||||
</tr>
|
</tr>
|
||||||
}
|
}
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr class="cctr-total-row">
|
<tr class="cctr-total-row">
|
||||||
<td colspan="4">Total</td>
|
<td colspan="5">Total</td>
|
||||||
<td class="num">₹{{ txnTotal(filteredTxns, 'debit') | number: '1.2-2' }}</td>
|
<td class="num">₹{{ txnTotal(filteredTxns, 'debit') | number: '1.2-2' }}</td>
|
||||||
<td class="num">₹{{ txnTotal(filteredTxns, 'credit') | number: '1.2-2' }}</td>
|
<td class="num">₹{{ txnTotal(filteredTxns, 'credit') | number: '1.2-2' }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
+66
-32
@@ -34,6 +34,9 @@ interface Branch {
|
|||||||
name: string;
|
name: string;
|
||||||
/** Relative size vs the base dataset below (which represents the Head Office main branch, scale 1). */
|
/** Relative size vs the base dataset below (which represents the Head Office main branch, scale 1). */
|
||||||
scale: number;
|
scale: number;
|
||||||
|
/** Numeric offset used to derive this branch's own account numbers / IFSC serials — keeps the
|
||||||
|
* standard 12-digit / IFSC format intact instead of just tagging a prefix onto Branch 1's values. */
|
||||||
|
acctShift: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
type TabKey = 'cash' | 'transfer' | 'clearing' | 'digital';
|
type TabKey = 'cash' | 'transfer' | 'clearing' | 'digital';
|
||||||
@@ -84,8 +87,8 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
* of its own Transaction Details).
|
* of its own Transaction Details).
|
||||||
*/
|
*/
|
||||||
branches: Branch[] = [
|
branches: Branch[] = [
|
||||||
{ code: 'BR1', name: 'Branch 1', scale: 1 },
|
{ code: 'BR1', name: 'Branch 1', scale: 1, acctShift: 0 },
|
||||||
{ code: 'BR2', name: 'Branch 2', scale: 0.7 }
|
{ code: 'BR2', name: 'Branch 2', scale: 0.7, acctShift: 400 }
|
||||||
];
|
];
|
||||||
|
|
||||||
/** 'ALL' = consolidated across both branches; otherwise a Branch.code. Only meaningful for Head Office users. */
|
/** 'ALL' = consolidated across both branches; otherwise a Branch.code. Only meaningful for Head Office users. */
|
||||||
@@ -131,7 +134,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0141',
|
voucherNo: 'CSH/2607/0141',
|
||||||
accountNo: 'Teller-01',
|
accountNo: 'TIL-0001',
|
||||||
accountName: 'Teller Counter 1 Cash Deposits (Aggregated)',
|
accountName: 'Teller Counter 1 Cash Deposits (Aggregated)',
|
||||||
particulars: 'Cash Deposit - Savings/Current Accounts',
|
particulars: 'Cash Deposit - Savings/Current Accounts',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -140,7 +143,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0142',
|
voucherNo: 'CSH/2607/0142',
|
||||||
accountNo: 'Teller-02',
|
accountNo: 'TIL-0002',
|
||||||
accountName: 'Teller Counter 2 Cash Deposits (Aggregated)',
|
accountName: 'Teller Counter 2 Cash Deposits (Aggregated)',
|
||||||
particulars: 'Cash Deposit - Savings/Current Accounts',
|
particulars: 'Cash Deposit - Savings/Current Accounts',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -176,7 +179,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0146',
|
voucherNo: 'CSH/2607/0146',
|
||||||
accountNo: 'Branch ATM',
|
accountNo: 'ATM-0001',
|
||||||
accountName: 'ATM Excess Cash Retraction',
|
accountName: 'ATM Excess Cash Retraction',
|
||||||
particulars: 'Excess Cash Surrendered by ATM to Vault',
|
particulars: 'Excess Cash Surrendered by ATM to Vault',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -203,7 +206,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0149',
|
voucherNo: 'CSH/2607/0149',
|
||||||
accountNo: 'Branch ATM',
|
accountNo: 'ATM-0001',
|
||||||
accountName: 'ATM 1 Cash Loading',
|
accountName: 'ATM 1 Cash Loading',
|
||||||
particulars: 'Vault to ATM Cash Transfer',
|
particulars: 'Vault to ATM Cash Transfer',
|
||||||
debit: 700000,
|
debit: 700000,
|
||||||
@@ -212,7 +215,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0150',
|
voucherNo: 'CSH/2607/0150',
|
||||||
accountNo: 'Extension Counter ATM',
|
accountNo: 'ATM-0002',
|
||||||
accountName: 'ATM 2 Cash Loading',
|
accountName: 'ATM 2 Cash Loading',
|
||||||
particulars: 'Vault to ATM Cash Transfer',
|
particulars: 'Vault to ATM Cash Transfer',
|
||||||
debit: 500000,
|
debit: 500000,
|
||||||
@@ -239,7 +242,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0153',
|
voucherNo: 'CSH/2607/0153',
|
||||||
accountNo: 'Currency Chest',
|
accountNo: 'CCH-0001',
|
||||||
accountName: 'Currency Chest Remittance',
|
accountName: 'Currency Chest Remittance',
|
||||||
particulars: 'Surplus Cash Remitted to Currency Chest',
|
particulars: 'Surplus Cash Remitted to Currency Chest',
|
||||||
debit: 400000,
|
debit: 400000,
|
||||||
@@ -266,7 +269,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: '100001',
|
glCode: '100001',
|
||||||
voucherNo: 'CSH/2607/0156',
|
voucherNo: 'CSH/2607/0156',
|
||||||
accountNo: 'Vault',
|
accountNo: 'VLT-0001',
|
||||||
accountName: 'Vault Denomination Exchange Adjustment',
|
accountName: 'Vault Denomination Exchange Adjustment',
|
||||||
particulars: 'Shortage Adjustment - Denomination Exchange',
|
particulars: 'Shortage Adjustment - Denomination Exchange',
|
||||||
debit: 205000,
|
debit: 205000,
|
||||||
@@ -1171,7 +1174,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44521',
|
voucherNo: 'UPI/2607/44521',
|
||||||
accountNo: 'NPCI-UPI-SETL-IN-01',
|
accountNo: 'RRN-UPI26073100145',
|
||||||
accountName: 'UPI Inward Settlement - Morning Batch (00:00-12:00)',
|
accountName: 'UPI Inward Settlement - Morning Batch (00:00-12:00)',
|
||||||
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1180,7 +1183,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44522',
|
voucherNo: 'UPI/2607/44522',
|
||||||
accountNo: 'NPCI-UPI-SETL-IN-02',
|
accountNo: 'RRN-UPI26073100289',
|
||||||
accountName: 'UPI Inward Settlement - Afternoon Batch (12:00-18:00)',
|
accountName: 'UPI Inward Settlement - Afternoon Batch (12:00-18:00)',
|
||||||
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1189,7 +1192,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44523',
|
voucherNo: 'UPI/2607/44523',
|
||||||
accountNo: 'NPCI-UPI-SETL-IN-03',
|
accountNo: 'RRN-UPI26073100356',
|
||||||
accountName: 'UPI Inward Settlement - Evening Batch (18:00-24:00)',
|
accountName: 'UPI Inward Settlement - Evening Batch (18:00-24:00)',
|
||||||
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1198,7 +1201,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44524',
|
voucherNo: 'UPI/2607/44524',
|
||||||
accountNo: 'NPCI-UPI-SETL-OUT-01',
|
accountNo: 'RRN-UPI26073100478',
|
||||||
accountName: 'UPI Outward Settlement - Morning Batch (00:00-12:00)',
|
accountName: 'UPI Outward Settlement - Morning Batch (00:00-12:00)',
|
||||||
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
||||||
debit: 1850000,
|
debit: 1850000,
|
||||||
@@ -1207,7 +1210,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44525',
|
voucherNo: 'UPI/2607/44525',
|
||||||
accountNo: 'NPCI-UPI-SETL-OUT-02',
|
accountNo: 'RRN-UPI26073100512',
|
||||||
accountName: 'UPI Outward Settlement - Afternoon Batch (12:00-18:00)',
|
accountName: 'UPI Outward Settlement - Afternoon Batch (12:00-18:00)',
|
||||||
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
||||||
debit: 2050000,
|
debit: 2050000,
|
||||||
@@ -1216,7 +1219,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'UPI',
|
glCode: 'UPI',
|
||||||
voucherNo: 'UPI/2607/44526',
|
voucherNo: 'UPI/2607/44526',
|
||||||
accountNo: 'NPCI-UPI-SETL-OUT-03',
|
accountNo: 'RRN-UPI26073100634',
|
||||||
accountName: 'UPI Outward Settlement - Evening Batch (18:00-24:00)',
|
accountName: 'UPI Outward Settlement - Evening Batch (18:00-24:00)',
|
||||||
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)',
|
||||||
debit: 1490000,
|
debit: 1490000,
|
||||||
@@ -1226,7 +1229,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'ATM',
|
glCode: 'ATM',
|
||||||
voucherNo: 'ATM/2607/9081',
|
voucherNo: 'ATM/2607/9081',
|
||||||
accountNo: 'ATM-SETL-CR-01',
|
accountNo: 'RRN-ATM26073100118',
|
||||||
accountName: 'ATM Cash Deposits - Own Branch ATM (Aggregated)',
|
accountName: 'ATM Cash Deposits - Own Branch ATM (Aggregated)',
|
||||||
particulars: 'ATM Cash Deposit - Own Branch ATM',
|
particulars: 'ATM Cash Deposit - Own Branch ATM',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1235,7 +1238,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'ATM',
|
glCode: 'ATM',
|
||||||
voucherNo: 'ATM/2607/9082',
|
voucherNo: 'ATM/2607/9082',
|
||||||
accountNo: 'ATM-SETL-CR-02',
|
accountNo: 'RRN-ATM26073100224',
|
||||||
accountName: 'ATM Cash Deposits - Extension Counter ATM (Aggregated)',
|
accountName: 'ATM Cash Deposits - Extension Counter ATM (Aggregated)',
|
||||||
particulars: 'ATM Cash Deposit - Extension Counter ATM',
|
particulars: 'ATM Cash Deposit - Extension Counter ATM',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1244,7 +1247,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'ATM',
|
glCode: 'ATM',
|
||||||
voucherNo: 'ATM/2607/9083',
|
voucherNo: 'ATM/2607/9083',
|
||||||
accountNo: 'ATM-SETL-DR-01',
|
accountNo: 'RRN-ATM26073100337',
|
||||||
accountName: 'ATM Cash Withdrawals - Own Branch ATM (Aggregated)',
|
accountName: 'ATM Cash Withdrawals - Own Branch ATM (Aggregated)',
|
||||||
particulars: 'ATM Cash Withdrawal - Own Branch ATM',
|
particulars: 'ATM Cash Withdrawal - Own Branch ATM',
|
||||||
debit: 420000,
|
debit: 420000,
|
||||||
@@ -1253,7 +1256,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'ATM',
|
glCode: 'ATM',
|
||||||
voucherNo: 'ATM/2607/9084',
|
voucherNo: 'ATM/2607/9084',
|
||||||
accountNo: 'ATM-SETL-DR-02',
|
accountNo: 'RRN-ATM26073100449',
|
||||||
accountName: 'ATM Cash Withdrawals - Other Bank ATM, NFS Switch (Aggregated)',
|
accountName: 'ATM Cash Withdrawals - Other Bank ATM, NFS Switch (Aggregated)',
|
||||||
particulars: 'ATM Cash Withdrawal - Other Bank ATM (NFS)',
|
particulars: 'ATM Cash Withdrawal - Other Bank ATM (NFS)',
|
||||||
debit: 265000,
|
debit: 265000,
|
||||||
@@ -1263,7 +1266,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'NACH',
|
glCode: 'NACH',
|
||||||
voucherNo: 'NACH/2607/3304',
|
voucherNo: 'NACH/2607/3304',
|
||||||
accountNo: 'NACH-SETL-CR-01',
|
accountNo: 'UMRN-NACH26073100112',
|
||||||
accountName: 'NACH Credits - Corporate Payroll Disbursement (Aggregated)',
|
accountName: 'NACH Credits - Corporate Payroll Disbursement (Aggregated)',
|
||||||
particulars: 'NACH Credit - Salary Disbursement Batch',
|
particulars: 'NACH Credit - Salary Disbursement Batch',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1272,7 +1275,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'NACH',
|
glCode: 'NACH',
|
||||||
voucherNo: 'NACH/2607/3305',
|
voucherNo: 'NACH/2607/3305',
|
||||||
accountNo: 'NACH-SETL-CR-02',
|
accountNo: 'UMRN-NACH26073100156',
|
||||||
accountName: 'NACH Credits - Government Subsidy (DBT) Disbursement (Aggregated)',
|
accountName: 'NACH Credits - Government Subsidy (DBT) Disbursement (Aggregated)',
|
||||||
particulars: 'NACH Credit - Subsidy Disbursement Batch',
|
particulars: 'NACH Credit - Subsidy Disbursement Batch',
|
||||||
debit: 0,
|
debit: 0,
|
||||||
@@ -1281,7 +1284,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'NACH',
|
glCode: 'NACH',
|
||||||
voucherNo: 'NACH/2607/3306',
|
voucherNo: 'NACH/2607/3306',
|
||||||
accountNo: 'NACH-SETL-DR-01',
|
accountNo: 'UMRN-NACH26073100198',
|
||||||
accountName: 'NACH Debits - Retail Loan EMI Collection (Aggregated)',
|
accountName: 'NACH Debits - Retail Loan EMI Collection (Aggregated)',
|
||||||
particulars: 'NACH Debit - Loan EMI Collection Batch',
|
particulars: 'NACH Debit - Loan EMI Collection Batch',
|
||||||
debit: 560000,
|
debit: 560000,
|
||||||
@@ -1290,7 +1293,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
{
|
{
|
||||||
glCode: 'NACH',
|
glCode: 'NACH',
|
||||||
voucherNo: 'NACH/2607/3307',
|
voucherNo: 'NACH/2607/3307',
|
||||||
accountNo: 'NACH-SETL-DR-02',
|
accountNo: 'UMRN-NACH26073100233',
|
||||||
accountName: 'NACH Debits - Gold Loan EMI Collection (Aggregated)',
|
accountName: 'NACH Debits - Gold Loan EMI Collection (Aggregated)',
|
||||||
particulars: 'NACH Debit - Gold Loan EMI Collection Batch',
|
particulars: 'NACH Debit - Gold Loan EMI Collection Batch',
|
||||||
debit: 305000,
|
debit: 305000,
|
||||||
@@ -1298,9 +1301,14 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/** YYMM tag baked into every dummy voucher/reference number (e.g. "2607" for Jul 2026) — kept
|
||||||
|
* in sync with the real current date so it never goes stale in a future month. */
|
||||||
|
private dateTag = '2607';
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
this.asOnDate = `${String(d.getDate()).padStart(2, '0')}-${String(d.getMonth() + 1).padStart(2, '0')}-${d.getFullYear()}`;
|
this.asOnDate = `${String(d.getDate()).padStart(2, '0')}-${String(d.getMonth() + 1).padStart(2, '0')}-${d.getFullYear()}`;
|
||||||
|
this.dateTag = `${String(d.getFullYear()).slice(-2)}${String(d.getMonth() + 1).padStart(2, '0')}`;
|
||||||
|
|
||||||
const creds = this.auth.getCredentials();
|
const creds = this.auth.getCredentials();
|
||||||
this.isHeadOffice = this.auth.isHeadOfficeUser();
|
this.isHeadOffice = this.auth.isHeadOfficeUser();
|
||||||
@@ -1318,6 +1326,11 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Renders a voucher/reference number with the baked-in "2607" swapped for today's real YYMM tag. */
|
||||||
|
display(value: string): string {
|
||||||
|
return (value || '').replace(/2607/g, this.dateTag);
|
||||||
|
}
|
||||||
|
|
||||||
private baseRowsFor(tab: TabKey): SummaryRow[] {
|
private baseRowsFor(tab: TabKey): SummaryRow[] {
|
||||||
switch (tab) {
|
switch (tab) {
|
||||||
case 'cash':
|
case 'cash':
|
||||||
@@ -1355,15 +1368,36 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
return rows.map((r) => ({ ...r, opening: this.roundAmt(r.opening * factor) }));
|
return rows.map((r) => ({ ...r, opening: this.roundAmt(r.opening * factor) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
private scaleTxns(txns: TxnRow[], factor: number, branchTag?: string): TxnRow[] {
|
/**
|
||||||
if (factor === 1) {
|
* Re-derives a customer account number or bank IFSC code for a different branch by shifting
|
||||||
|
* its numeric segment — NOT by tagging a prefix onto Branch 1's value, since real account
|
||||||
|
* numbers and IFSC codes have a fixed, standard shape and a "BR2-" prefix would look fake.
|
||||||
|
* Everything else (UTR/RRN/UMRN/DD/PO/TDS/GST/cheque/branch/settlement references) keeps the
|
||||||
|
* simpler branch-tag prefix, since those are already free-form internal reference formats.
|
||||||
|
*/
|
||||||
|
private scaleAccountNo(accountNo: string, branch: Branch): string {
|
||||||
|
if (/^\d{12}$/.test(accountNo)) {
|
||||||
|
const branchSeg = (parseInt(accountNo.slice(0, 3), 10) + branch.acctShift) % 1000;
|
||||||
|
return String(branchSeg).padStart(3, '0') + accountNo.slice(3);
|
||||||
|
}
|
||||||
|
const ifsc = accountNo.match(/^([A-Z]{4}0)(\d{6})$/);
|
||||||
|
if (ifsc) {
|
||||||
|
const serial = (parseInt(ifsc[2], 10) + branch.acctShift) % 1000000;
|
||||||
|
return ifsc[1] + String(serial).padStart(6, '0');
|
||||||
|
}
|
||||||
|
return `${branch.code}-${accountNo}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private scaleTxns(txns: TxnRow[], branch: Branch | null): TxnRow[] {
|
||||||
|
if (!branch || branch.scale === 1) {
|
||||||
return txns;
|
return txns;
|
||||||
}
|
}
|
||||||
return txns.map((t) => ({
|
return txns.map((t) => ({
|
||||||
...t,
|
...t,
|
||||||
voucherNo: branchTag ? `${branchTag}-${t.voucherNo}` : t.voucherNo,
|
voucherNo: `${branch.code}-${t.voucherNo}`,
|
||||||
debit: this.roundAmt(t.debit * factor),
|
accountNo: this.scaleAccountNo(t.accountNo, branch),
|
||||||
credit: this.roundAmt(t.credit * factor)
|
debit: this.roundAmt(t.debit * branch.scale),
|
||||||
|
credit: this.roundAmt(t.credit * branch.scale)
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1387,13 +1421,13 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
private effectiveTxns(tab: TabKey): TxnRow[] {
|
private effectiveTxns(tab: TabKey): TxnRow[] {
|
||||||
const base = this.baseTxnsFor(tab);
|
const base = this.baseTxnsFor(tab);
|
||||||
if (!this.isHeadOffice) {
|
if (!this.isHeadOffice) {
|
||||||
return this.ownBranch ? this.scaleTxns(base, this.ownBranch.scale, this.ownBranch.code) : base;
|
return this.scaleTxns(base, this.ownBranch);
|
||||||
}
|
}
|
||||||
if (this.selectedBranchCode === 'ALL') {
|
if (this.selectedBranchCode === 'ALL') {
|
||||||
return this.branches.flatMap((b) => this.scaleTxns(base, b.scale, b.code));
|
return this.branches.flatMap((b) => this.scaleTxns(base, b));
|
||||||
}
|
}
|
||||||
const branch = this.branches.find((b) => b.code === this.selectedBranchCode);
|
const branch = this.branches.find((b) => b.code === this.selectedBranchCode);
|
||||||
return this.scaleTxns(base, branch ? branch.scale : 1, branch?.code);
|
return this.scaleTxns(base, branch ?? null);
|
||||||
}
|
}
|
||||||
|
|
||||||
get rowsForActiveTab(): SummaryRow[] {
|
get rowsForActiveTab(): SummaryRow[] {
|
||||||
@@ -1524,7 +1558,7 @@ export class CashClearingTransferSummaryComponent {
|
|||||||
return this.branches.map((b) => {
|
return this.branches.map((b) => {
|
||||||
const pairs = this.allTabs.map((tab) => ({
|
const pairs = this.allTabs.map((tab) => ({
|
||||||
rows: this.scaleRows(this.baseRowsFor(tab), b.scale),
|
rows: this.scaleRows(this.baseRowsFor(tab), b.scale),
|
||||||
txns: this.scaleTxns(this.baseTxnsFor(tab), b.scale, b.code)
|
txns: this.scaleTxns(this.baseTxnsFor(tab), b)
|
||||||
}));
|
}));
|
||||||
const opening = pairs.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'opening'), 0);
|
const opening = pairs.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'opening'), 0);
|
||||||
const credit = pairs.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'credit'), 0);
|
const credit = pairs.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'credit'), 0);
|
||||||
|
|||||||
@@ -533,6 +533,8 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
screeningLogId: number | null = null;
|
screeningLogId: number | null = null;
|
||||||
/** Snapshot of the name that was last verified — used to invalidate verification when name changes */
|
/** Snapshot of the name that was last verified — used to invalidate verification when name changes */
|
||||||
private verifiedName: string = '';
|
private verifiedName: string = '';
|
||||||
|
/** True while prefillForEdit() is patching historical monthly/annual values — see linkMonthlyAnnual(). */
|
||||||
|
private suppressMonthlyAnnualLink = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {FormBuilder} formBuilder Form Builder
|
* @param {FormBuilder} formBuilder Form Builder
|
||||||
@@ -709,6 +711,12 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
const data = this.clientData;
|
const data = this.clientData;
|
||||||
this.loadExistingSeniorPwdDocuments();
|
this.loadExistingSeniorPwdDocuments();
|
||||||
|
|
||||||
|
// Loading an existing client's independently-saved monthly/annual values must not run
|
||||||
|
// through the auto-calc in linkMonthlyAnnual() — patching monthlyIncome then annualIncome
|
||||||
|
// (or vice versa) would otherwise have each overwrite the other via its valueChanges,
|
||||||
|
// instead of keeping the exact historical values as saved.
|
||||||
|
this.suppressMonthlyAnnualLink = true;
|
||||||
|
|
||||||
// Patch all base controls that exist on the form
|
// Patch all base controls that exist on the form
|
||||||
this.createClientForm.patchValue({
|
this.createClientForm.patchValue({
|
||||||
officeId: data.officeId,
|
officeId: data.officeId,
|
||||||
@@ -743,6 +751,7 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
? new Date(data.timeline.submittedOnDate)
|
? new Date(data.timeline.submittedOnDate)
|
||||||
: this.settingsService.businessDate
|
: this.settingsService.businessDate
|
||||||
});
|
});
|
||||||
|
this.suppressMonthlyAnnualLink = false;
|
||||||
|
|
||||||
// Patch name fields (already created by buildDependencies via legalFormId subscription)
|
// Patch name fields (already created by buildDependencies via legalFormId subscription)
|
||||||
const legalFormId = data.legalForm?.id || LegalFormId.PERSON;
|
const legalFormId = data.legalForm?.id || LegalFormId.PERSON;
|
||||||
@@ -954,6 +963,43 @@ export class ClientGeneralStepComponent implements OnInit, OnDestroy, OnChanges
|
|||||||
Validators.required
|
Validators.required
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.linkMonthlyAnnual('monthlyIncome', 'annualIncome');
|
||||||
|
this.linkMonthlyAnnual('monthlyTurnover', 'annualTurnover');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keeps a Monthly/Annual pair of amount fields in sync at a 12x ratio — typing into either
|
||||||
|
* one auto-fills the other. Uses { emitEvent: false } on the write side so the two
|
||||||
|
* subscriptions don't trigger each other back and forth.
|
||||||
|
*/
|
||||||
|
/** Rounds to at most 2 decimals without padding whole numbers with a trailing ".00". */
|
||||||
|
private round2(n: number): string {
|
||||||
|
return (Math.round(n * 100) / 100).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private linkMonthlyAnnual(monthlyControlName: string, annualControlName: string): void {
|
||||||
|
const monthly = this.createClientForm.get(monthlyControlName);
|
||||||
|
const annual = this.createClientForm.get(annualControlName);
|
||||||
|
if (!monthly || !annual) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
monthly.valueChanges.subscribe((value) => {
|
||||||
|
if (this.suppressMonthlyAnnualLink) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const num = parseFloat(value);
|
||||||
|
annual.setValue(!isNaN(num) && num >= 0 ? this.round2(num * 12) : '', { emitEvent: false });
|
||||||
|
});
|
||||||
|
|
||||||
|
annual.valueChanges.subscribe((value) => {
|
||||||
|
if (this.suppressMonthlyAnnualLink) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const num = parseFloat(value);
|
||||||
|
monthly.setValue(!isNaN(num) && num >= 0 ? this.round2(num / 12) : '', { emitEvent: false });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user