/** * 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/. */ import { Component, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { AuthenticationService } from '../../core/authentication/authentication.service'; import { ExportSheetSpec, exportWorkbook } from '../cashier-export'; interface SummaryRow { code: string; name: string; /** Balance carried forward as of the start of the day — the only figure NOT derived from txns below. */ opening: number; } interface TxnRow { /** Links this transaction to the SummaryRow.code it posts against — the single source of truth for Credit/Debit totals. */ glCode: string; voucherNo: string; accountNo: string; accountName: string; particulars: string; debit: number; credit: number; } interface Branch { code: string; name: string; /** Relative size vs the base dataset below (which represents the Head Office main branch, scale 1). */ 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'; /** * Dummy static Cash / Clearing / Transfer summary + transaction-detail report. * * IMPORTANT: Credit/Debit (and therefore Closing) are always DERIVED from the txn * lists below (rowCredit/rowDebit), never hand-entered separately — this guarantees * the Summary view and the Transaction Details view can never go out of sync, * for any branch or for the Head Office's "All Branches" consolidated view. */ @Component({ selector: 'mifosx-cash-clearing-transfer-summary', templateUrl: './cash-clearing-transfer-summary.component.html', styleUrls: [ '../cashier-shared.scss', './cash-clearing-transfer-summary.component.scss' ], standalone: true, imports: [ CommonModule, FormsModule ] }) export class CashClearingTransferSummaryComponent { private auth = inject(AuthenticationService); asOnDate = ''; activeTab: TabKey = 'cash'; showDetails = false; /** GL/channel filter for the Transaction Details view — null means "All". */ glFilter: string | null = null; /** True while an Export to Excel workbook is being built — disables the button to prevent double-clicks. */ generating = false; private readonly tabLabels: Record = { cash: 'Cash', transfer: 'Transfer', clearing: 'Clearing', digital: 'Digital' }; /** True when the logged-in user belongs to the Head Office (sees both branches + consolidated view). */ isHeadOffice = false; /** The logged-in user's own branch/office name, from real session credentials. */ currentOfficeName = 'Branch Office'; /** Set when a branch-level login's officeName matches one of the two dummy branches below. */ private ownBranch: Branch | null = null; /** * The two branches this demo covers. A branch-level user is matched to one of these by * their real officeName (case-insensitive substring match) so "Branch 1" logging in sees * Branch 1's figures and "Branch 2" sees Branch 2's — rename these to your real office * names if they differ. Both are proportionally scaled from the same base dataset so * every branch's own numbers stay internally consistent (Summary always equals the sum * of its own Transaction Details). */ branches: Branch[] = [ { code: 'BR1', name: 'Branch 1', scale: 1, acctShift: 0 }, { 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. */ selectedBranchCode = 'ALL'; cashRows: SummaryRow[] = [{ code: '100001', name: 'Cash at Vault', opening: 3572000 }]; transferRows: SummaryRow[] = [ { code: '250101', name: 'Suspense Account - Transfer', opening: 85000 }, { code: '250102', name: 'Sundry Deposit Account', opening: 132500 }, { code: '250103', name: 'Inter Branch Account (Head Office)', opening: 610000 }, { code: '250104', name: 'Inward Remittance Suspense', opening: 42000 }, { code: '250105', name: 'Outward Remittance Suspense', opening: 38500 }, { code: '251001', name: 'Bank GL - SBI Current Account', opening: 1850000 }, { code: '251002', name: 'Bank GL - HDFC Bank Current Account', opening: 960000 }, { code: '251003', name: 'Bank GL - ICICI Bank Current Account', opening: 745000 }, { code: '251004', name: 'Bank GL - Axis Bank Current Account', opening: 512000 }, { code: '252001', name: 'DD Payable Account', opening: 96000 }, { code: '252002', name: 'Pay Order Payable Account', opening: 64000 }, { code: '253001', name: 'Sundry Creditors', opening: 158000 }, { code: '253002', name: 'Sundry Debtors', opening: 121000 }, { code: '254001', name: 'TDS Payable Account', opening: 28500 }, { code: '254002', name: 'GST Payable Account', opening: 19500 } ]; clearingRows: SummaryRow[] = [ { code: '300201', name: 'Outward Clearing (Cheques Sent)', opening: 265000 }, { code: '300202', name: 'Inward Clearing (Cheques Received)', opening: 198000 }, { code: '300203', name: 'Clearing Suspense Account', opening: 15500 }, { code: '300204', name: 'CTS Clearing Difference Account', opening: 4200 }, { code: '300205', name: 'Local Clearing House Account', opening: 88000 } ]; digitalRows: SummaryRow[] = [ { code: 'RTGS', name: 'RTGS - Overall', opening: 720000 }, { code: 'NEFT', name: 'NEFT - Overall', opening: 512000 }, { code: 'UPI', name: 'UPI - Overall', opening: 96000 }, { code: 'ATM', name: 'ATM - Overall', opening: 340000 }, { code: 'NACH', name: 'NACH - Overall', opening: 158000 } ]; cashTxns: TxnRow[] = [ { glCode: '100001', voucherNo: 'CSH/2607/0141', accountNo: 'TIL-0001', accountName: 'Teller Counter 1 Cash Deposits (Aggregated)', particulars: 'Cash Deposit - Savings/Current Accounts', debit: 0, credit: 950000 }, { glCode: '100001', voucherNo: 'CSH/2607/0142', accountNo: 'TIL-0002', accountName: 'Teller Counter 2 Cash Deposits (Aggregated)', particulars: 'Cash Deposit - Savings/Current Accounts', debit: 0, credit: 700000 }, { glCode: '100001', voucherNo: 'CSH/2607/0143', accountNo: '015020198765', accountName: 'Anita Traders', particulars: 'Cash Deposit - Current Account', debit: 0, credit: 185000 }, { glCode: '100001', voucherNo: 'CSH/2607/0144', accountNo: '015010112345', accountName: 'Ramesh Kumar Sahu', particulars: 'Cash Deposit - Savings Account', debit: 0, credit: 25000 }, { glCode: '100001', voucherNo: 'CSH/2607/0145', accountNo: '015020209988', accountName: 'Kavita Enterprises', particulars: 'Cash Deposit - Current Account', debit: 0, credit: 110000 }, { glCode: '100001', voucherNo: 'CSH/2607/0146', accountNo: 'ATM-0001', accountName: 'ATM Excess Cash Retraction', particulars: 'Excess Cash Surrendered by ATM to Vault', debit: 0, credit: 400000 }, { glCode: '100001', voucherNo: 'CSH/2607/0147', accountNo: '015010223344', accountName: 'Suresh Yadav', particulars: 'Cash Deposit - Savings Account', debit: 0, credit: 15000 }, { glCode: '100001', voucherNo: 'CSH/2607/0148', accountNo: '015030112233', accountName: 'Kiran Bhosale', particulars: 'Cash Deposit - RD Installment', debit: 0, credit: 130000 }, { glCode: '100001', voucherNo: 'CSH/2607/0149', accountNo: 'ATM-0001', accountName: 'ATM 1 Cash Loading', particulars: 'Vault to ATM Cash Transfer', debit: 700000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0150', accountNo: 'ATM-0002', accountName: 'ATM 2 Cash Loading', particulars: 'Vault to ATM Cash Transfer', debit: 500000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0151', accountNo: '015010154321', accountName: 'Sunita Devi', particulars: 'Cash Withdrawal - Savings Account', debit: 12000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0152', accountNo: '015010167890', accountName: 'Mohan Lal Verma', particulars: 'Cash Withdrawal - Term Deposit Closure', debit: 75000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0153', accountNo: 'CCH-0001', accountName: 'Currency Chest Remittance', particulars: 'Surplus Cash Remitted to Currency Chest', debit: 400000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0154', accountNo: '015020278899', accountName: 'Prakash Jadhav', particulars: 'Cash Withdrawal - Current Account', debit: 210000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0155', accountNo: '015010289900', accountName: 'Snehal Kulkarni', particulars: 'Cash Withdrawal - Savings Account', debit: 18000, credit: 0 }, { glCode: '100001', voucherNo: 'CSH/2607/0156', accountNo: 'VLT-0001', accountName: 'Vault Denomination Exchange Adjustment', particulars: 'Shortage Adjustment - Denomination Exchange', debit: 205000, credit: 0 } ]; transferTxns: TxnRow[] = [ // 250101 - Suspense Account - Transfer (credit 420000 / debit 398000) { glCode: '250101', voucherNo: 'TRF/2607/0101', accountNo: '015020145678', accountName: 'Vikram Traders', particulars: 'Suspense Recovered - Vikram Traders', debit: 0, credit: 250000 }, { glCode: '250101', voucherNo: 'TRF/2607/0102', accountNo: '015020145991', accountName: 'Rohit Sharma', particulars: 'Suspense Recovered - Rohit Sharma', debit: 0, credit: 170000 }, { glCode: '250101', voucherNo: 'TRF/2607/0103', accountNo: '015020156432', accountName: 'Meena Enterprises', particulars: 'Suspense Adjustment - Meena Enterprises', debit: 230000, credit: 0 }, { glCode: '250101', voucherNo: 'TRF/2607/0104', accountNo: '015020156877', accountName: 'Kavita Singh', particulars: 'Suspense Adjustment - Kavita Singh', debit: 168000, credit: 0 }, // 250102 - Sundry Deposit Account (credit 96000 / debit 110000) { glCode: '250102', voucherNo: 'TRF/2607/0105', accountNo: '015020167531', accountName: 'Ashok Furnitures', particulars: 'Sundry Deposit Received - Ashok Furnitures', debit: 0, credit: 60000 }, { glCode: '250102', voucherNo: 'TRF/2607/0106', accountNo: '015020167998', accountName: 'Ganesh Traders', particulars: 'Sundry Deposit Received - Ganesh Traders', debit: 0, credit: 36000 }, { glCode: '250102', voucherNo: 'TRF/2607/0107', accountNo: '015020178654', accountName: 'Geeta Boutique', particulars: 'Sundry Deposit Refunded - Geeta Boutique', debit: 70000, credit: 0 }, { glCode: '250102', voucherNo: 'TRF/2607/0108', accountNo: '015020178901', accountName: 'Manisha Enterprises', particulars: 'Sundry Deposit Refunded - Manisha Enterprises', debit: 40000, credit: 0 }, // 250103 - Inter Branch Account, Head Office (credit 1250000 / debit 1180000) { glCode: '250103', voucherNo: 'TRF/2607/0109', accountNo: 'BR-0007', accountName: 'Andheri Branch (Branch Code 0007)', particulars: 'Funds Received from Andheri Branch', debit: 0, credit: 750000 }, { glCode: '250103', voucherNo: 'TRF/2607/0110', accountNo: 'BR-0015', accountName: 'Dadar Branch (Branch Code 0015)', particulars: 'Funds Received from Dadar Branch', debit: 0, credit: 500000 }, { glCode: '250103', voucherNo: 'TRF/2607/0111', accountNo: 'BR-0012', accountName: 'Powai Branch (Branch Code 0012)', particulars: 'Fund Transfer to Powai Branch', debit: 680000, credit: 0 }, { glCode: '250103', voucherNo: 'TRF/2607/0112', accountNo: 'BR-0019', accountName: 'Thane Branch (Branch Code 0019)', particulars: 'Fund Transfer to Thane Branch', debit: 500000, credit: 0 }, // 250104 - Inward Remittance Suspense (credit 315000 / debit 300000) { glCode: '250104', voucherNo: 'TRF/2607/0113', accountNo: '015020189712', accountName: 'Suresh Patil', particulars: 'Inward Remittance Received - Suresh Patil', debit: 0, credit: 190000 }, { glCode: '250104', voucherNo: 'TRF/2607/0114', accountNo: '015020189834', accountName: 'Rahul Deshmukh', particulars: 'Inward Remittance Received - Rahul Deshmukh', debit: 0, credit: 125000 }, { glCode: '250104', voucherNo: 'TRF/2607/0115', accountNo: '015020190845', accountName: 'Lata Joshi', particulars: 'Inward Remittance Credited - Lata Joshi', debit: 175000, credit: 0 }, { glCode: '250104', voucherNo: 'TRF/2607/0116', accountNo: '015020190956', accountName: 'Farhan Sheikh', particulars: 'Inward Remittance Credited - Farhan Sheikh', debit: 125000, credit: 0 }, // 250105 - Outward Remittance Suspense (credit 275000 / debit 260000) { glCode: '250105', voucherNo: 'TRF/2607/0117', accountNo: '015020201456', accountName: 'Anil Kapoor Traders', particulars: 'Outward Remittance Booked - Anil Kapoor Traders', debit: 0, credit: 160000 }, { glCode: '250105', voucherNo: 'TRF/2607/0118', accountNo: '015020201567', accountName: 'Sameer Qureshi', particulars: 'Outward Remittance Booked - Sameer Qureshi', debit: 0, credit: 115000 }, { glCode: '250105', voucherNo: 'TRF/2607/0119', accountNo: '015020212789', accountName: 'Deepa Enterprises', particulars: 'Outward Remittance Settled - Deepa Enterprises', debit: 150000, credit: 0 }, { glCode: '250105', voucherNo: 'TRF/2607/0120', accountNo: '015020212890', accountName: 'Yogesh Pawar', particulars: 'Outward Remittance Settled - Yogesh Pawar', debit: 110000, credit: 0 }, // 251001 - Bank GL - SBI Current Account (credit 3250000 / debit 2980000) { glCode: '251001', voucherNo: 'TRF/2607/0121', accountNo: 'SBIN0001234', accountName: 'SBI Mumbai Main Branch', particulars: 'Inward Settlement via SBI Current A/c', debit: 0, credit: 1500000 }, { glCode: '251001', voucherNo: 'TRF/2607/0122', accountNo: 'SBIN0002211', accountName: 'SBI Andheri Branch', particulars: 'Inward Settlement via SBI Current A/c', debit: 0, credit: 1000000 }, { glCode: '251001', voucherNo: 'TRF/2607/0123', accountNo: 'SBIN0003322', accountName: 'SBI Thane Branch', particulars: 'Inward Settlement via SBI Current A/c', debit: 0, credit: 750000 }, { glCode: '251001', voucherNo: 'TRF/2607/0124', accountNo: 'SBIN0005678', accountName: 'SBI Pune Branch', particulars: 'Outward Settlement via SBI Current A/c', debit: 1400000, credit: 0 }, { glCode: '251001', voucherNo: 'TRF/2607/0125', accountNo: 'SBIN0006689', accountName: 'SBI Nashik Branch', particulars: 'Outward Settlement via SBI Current A/c', debit: 900000, credit: 0 }, { glCode: '251001', voucherNo: 'TRF/2607/0126', accountNo: 'SBIN0007790', accountName: 'SBI Nagpur Branch', particulars: 'Outward Settlement via SBI Current A/c', debit: 680000, credit: 0 }, // 251002 - Bank GL - HDFC Bank Current Account (credit 1840000 / debit 1725000) { glCode: '251002', voucherNo: 'TRF/2607/0127', accountNo: 'HDFC0002345', accountName: 'HDFC Bank Andheri Branch', particulars: 'Inward Settlement via HDFC Current A/c', debit: 0, credit: 900000 }, { glCode: '251002', voucherNo: 'TRF/2607/0128', accountNo: 'HDFC0003456', accountName: 'HDFC Bank Bandra Branch', particulars: 'Inward Settlement via HDFC Current A/c', debit: 0, credit: 600000 }, { glCode: '251002', voucherNo: 'TRF/2607/0129', accountNo: 'HDFC0004567', accountName: 'HDFC Bank Malad Branch', particulars: 'Inward Settlement via HDFC Current A/c', debit: 0, credit: 340000 }, { glCode: '251002', voucherNo: 'TRF/2607/0130', accountNo: 'HDFC0006789', accountName: 'HDFC Bank Borivali Branch', particulars: 'Outward Settlement via HDFC Current A/c', debit: 800000, credit: 0 }, { glCode: '251002', voucherNo: 'TRF/2607/0131', accountNo: 'HDFC0007890', accountName: 'HDFC Bank Goregaon Branch', particulars: 'Outward Settlement via HDFC Current A/c', debit: 600000, credit: 0 }, { glCode: '251002', voucherNo: 'TRF/2607/0132', accountNo: 'HDFC0008901', accountName: 'HDFC Bank Kandivali Branch', particulars: 'Outward Settlement via HDFC Current A/c', debit: 325000, credit: 0 }, // 251003 - Bank GL - ICICI Bank Current Account (credit 1420000 / debit 1360000) { glCode: '251003', voucherNo: 'TRF/2607/0133', accountNo: 'ICIC0003456', accountName: 'ICICI Bank Thane Branch', particulars: 'Inward Settlement via ICICI Current A/c', debit: 0, credit: 820000 }, { glCode: '251003', voucherNo: 'TRF/2607/0134', accountNo: 'ICIC0004567', accountName: 'ICICI Bank Ghatkopar Branch', particulars: 'Inward Settlement via ICICI Current A/c', debit: 0, credit: 600000 }, { glCode: '251003', voucherNo: 'TRF/2607/0135', accountNo: 'ICIC0007890', accountName: 'ICICI Bank Vashi Branch', particulars: 'Outward Settlement via ICICI Current A/c', debit: 760000, credit: 0 }, { glCode: '251003', voucherNo: 'TRF/2607/0136', accountNo: 'ICIC0008901', accountName: 'ICICI Bank Chembur Branch', particulars: 'Outward Settlement via ICICI Current A/c', debit: 600000, credit: 0 }, // 251004 - Bank GL - Axis Bank Current Account (credit 980000 / debit 905000) { glCode: '251004', voucherNo: 'TRF/2607/0137', accountNo: 'UTIB0004567', accountName: 'Axis Bank Dadar Branch', particulars: 'Inward Settlement via Axis Current A/c', debit: 0, credit: 560000 }, { glCode: '251004', voucherNo: 'TRF/2607/0138', accountNo: 'UTIB0005678', accountName: 'Axis Bank Sion Branch', particulars: 'Inward Settlement via Axis Current A/c', debit: 0, credit: 420000 }, { glCode: '251004', voucherNo: 'TRF/2607/0139', accountNo: 'UTIB0008901', accountName: 'Axis Bank Kurla Branch', particulars: 'Outward Settlement via Axis Current A/c', debit: 505000, credit: 0 }, { glCode: '251004', voucherNo: 'TRF/2607/0140', accountNo: 'UTIB0009012', accountName: 'Axis Bank Ghansoli Branch', particulars: 'Outward Settlement via Axis Current A/c', debit: 400000, credit: 0 }, // 252001 - DD Payable Account (credit 240000 / debit 218000) { glCode: '252001', voucherNo: 'TRF/2607/0141', accountNo: 'DD/2607/5541', accountName: 'Sanjay Mehta', particulars: 'Demand Draft Issued - Sanjay Mehta', debit: 0, credit: 140000 }, { glCode: '252001', voucherNo: 'TRF/2607/0142', accountNo: 'DD/2607/5556', accountName: 'Farida Sheikh', particulars: 'Demand Draft Issued - Farida Sheikh', debit: 0, credit: 100000 }, { glCode: '252001', voucherNo: 'TRF/2607/0143', accountNo: 'DD/2607/5498', accountName: 'Rekha Nair', particulars: 'Demand Draft Paid - Rekha Nair', debit: 128000, credit: 0 }, { glCode: '252001', voucherNo: 'TRF/2607/0144', accountNo: 'DD/2607/5487', accountName: 'Girish Rao', particulars: 'Demand Draft Paid - Girish Rao', debit: 90000, credit: 0 }, // 252002 - Pay Order Payable Account (credit 175000 / debit 160000) { glCode: '252002', voucherNo: 'TRF/2607/0145', accountNo: 'PO/2607/1187', accountName: 'Arvind Traders', particulars: 'Pay Order Issued - Arvind Traders', debit: 0, credit: 100000 }, { glCode: '252002', voucherNo: 'TRF/2607/0146', accountNo: 'PO/2607/1192', accountName: 'Neelam Gupta', particulars: 'Pay Order Issued - Neelam Gupta', debit: 0, credit: 75000 }, { glCode: '252002', voucherNo: 'TRF/2607/0147', accountNo: 'PO/2607/1145', accountName: 'Vandana Enterprises', particulars: 'Pay Order Paid - Vandana Enterprises', debit: 95000, credit: 0 }, { glCode: '252002', voucherNo: 'TRF/2607/0148', accountNo: 'PO/2607/1138', accountName: 'Tushar Bhatt', particulars: 'Pay Order Paid - Tushar Bhatt', debit: 65000, credit: 0 }, // 253001 - Sundry Creditors (credit 92000 / debit 85000) { glCode: '253001', voucherNo: 'TRF/2607/0149', accountNo: '015020223412', accountName: 'Om Stationery Suppliers', particulars: 'Vendor Bill Provided For - Om Stationery Suppliers', debit: 0, credit: 52000 }, { glCode: '253001', voucherNo: 'TRF/2607/0150', accountNo: '015020223567', accountName: 'Shubham Printers', particulars: 'Vendor Bill Provided For - Shubham Printers', debit: 0, credit: 40000 }, { glCode: '253001', voucherNo: 'TRF/2607/0151', accountNo: '015020234598', accountName: 'Shree Balaji AMC Services', particulars: 'Vendor Payment - AMC Charges', debit: 50000, credit: 0 }, { glCode: '253001', voucherNo: 'TRF/2607/0152', accountNo: '015020234678', accountName: 'Metro Security Services', particulars: 'Vendor Payment - Security Services', debit: 35000, credit: 0 }, // 253002 - Sundry Debtors (credit 68000 / debit 74000) { glCode: '253002', voucherNo: 'TRF/2607/0153', accountNo: '015020245671', accountName: 'Kiran Hardware', particulars: 'Recovery from Sundry Debtor - Kiran Hardware', debit: 0, credit: 40000 }, { glCode: '253002', voucherNo: 'TRF/2607/0154', accountNo: '015020245789', accountName: 'Vishal Electronics', particulars: 'Recovery from Sundry Debtor - Vishal Electronics', debit: 0, credit: 28000 }, { glCode: '253002', voucherNo: 'TRF/2607/0155', accountNo: '015020256784', accountName: 'Nilesh Electricals', particulars: 'Advance Given to Sundry Debtor - Nilesh Electricals', debit: 44000, credit: 0 }, { glCode: '253002', voucherNo: 'TRF/2607/0156', accountNo: '015020256890', accountName: 'Ramdas Plumbing Works', particulars: 'Advance Given to Sundry Debtor - Ramdas Plumbing Works', debit: 30000, credit: 0 }, // 254001 - TDS Payable Account (credit 46000 / debit 40000) { glCode: '254001', voucherNo: 'TRF/2607/0157', accountNo: 'TDS/2607/9911', accountName: 'TDS on FD Interest Payouts', particulars: 'TDS Deducted on FD Interest Payouts', debit: 0, credit: 28000 }, { glCode: '254001', voucherNo: 'TRF/2607/0158', accountNo: 'TDS/2607/9917', accountName: 'TDS on RD Interest Payouts', particulars: 'TDS Deducted on RD Interest Payouts', debit: 0, credit: 18000 }, { glCode: '254001', voucherNo: 'TRF/2607/0159', accountNo: 'TDS/2607/9902', accountName: 'Income Tax Department', particulars: 'TDS Remitted to Government - Quarterly Challan', debit: 24000, credit: 0 }, { glCode: '254001', voucherNo: 'TRF/2607/0160', accountNo: 'TDS/2607/9903', accountName: 'Income Tax Department', particulars: 'TDS Remitted to Government - Adjustment Challan', debit: 16000, credit: 0 }, // 254002 - GST Payable Account (credit 38000 / debit 32000) { glCode: '254002', voucherNo: 'TRF/2607/0161', accountNo: 'GST/2607/7731', accountName: 'GST on Service Charges', particulars: 'GST Collected on Service Charges', debit: 0, credit: 22000 }, { glCode: '254002', voucherNo: 'TRF/2607/0162', accountNo: 'GST/2607/7736', accountName: 'GST on Locker Rent', particulars: 'GST Collected on Locker Rent', debit: 0, credit: 16000 }, { glCode: '254002', voucherNo: 'TRF/2607/0163', accountNo: 'GST/2607/7702', accountName: 'GST Department', particulars: 'GST Remitted to Government - Monthly Return', debit: 19000, credit: 0 }, { glCode: '254002', voucherNo: 'TRF/2607/0164', accountNo: 'GST/2607/7703', accountName: 'GST Department', particulars: 'GST Remitted to Government - Late Fee Adjustment', debit: 13000, credit: 0 } ]; clearingTxns: TxnRow[] = [ // 300201 - Outward Clearing, Cheques Sent (credit 980000 / debit 910000) { glCode: '300201', voucherNo: 'CLR/2607/0031', accountNo: 'CHQ-000123', accountName: 'Rajesh Kumar Singh', particulars: 'Cheque No 000123 Sent - Rajesh Kumar Singh', debit: 0, credit: 550000 }, { glCode: '300201', voucherNo: 'CLR/2607/0032', accountNo: 'CHQ-000129', accountName: 'Manoj Tiwari', particulars: 'Cheque No 000129 Sent - Manoj Tiwari', debit: 0, credit: 430000 }, { glCode: '300201', voucherNo: 'CLR/2607/0033', accountNo: 'CHQ-000145', accountName: 'Nisha Agarwal', particulars: 'Outward Clearing Realised - Nisha Agarwal', debit: 520000, credit: 0 }, { glCode: '300201', voucherNo: 'CLR/2607/0034', accountNo: 'CHQ-000151', accountName: 'Devendra Kale', particulars: 'Outward Clearing Realised - Devendra Kale', debit: 390000, credit: 0 }, // 300202 - Inward Clearing, Cheques Received (credit 875000 / debit 820000) { glCode: '300202', voucherNo: 'CLR/2607/0035', accountNo: 'CHQ-000456', accountName: 'Sameer Joshi', particulars: 'Cheque No 000456 Received - Sameer Joshi', debit: 0, credit: 500000 }, { glCode: '300202', voucherNo: 'CLR/2607/0036', accountNo: 'CHQ-000461', accountName: 'Ritu Bansal', particulars: 'Cheque No 000461 Received - Ritu Bansal', debit: 0, credit: 375000 }, { glCode: '300202', voucherNo: 'CLR/2607/0037', accountNo: 'CHQ-000478', accountName: 'Pooja Malhotra', particulars: 'Inward Clearing Passed for Payment - Pooja Malhotra', debit: 470000, credit: 0 }, { glCode: '300202', voucherNo: 'CLR/2607/0038', accountNo: 'CHQ-000483', accountName: 'Ajit Naik', particulars: 'Inward Clearing Passed for Payment - Ajit Naik', debit: 350000, credit: 0 }, // 300203 - Clearing Suspense Account (credit 60000 / debit 58000) { glCode: '300203', voucherNo: 'CLR/2607/0039', accountNo: 'CHQ-000512', accountName: 'ABC Enterprises', particulars: 'Clearing Difference Booked - ABC Enterprises', debit: 0, credit: 35000 }, { glCode: '300203', voucherNo: 'CLR/2607/0040', accountNo: 'CHQ-000519', accountName: 'Global Traders', particulars: 'Clearing Difference Booked - Global Traders', debit: 0, credit: 25000 }, { glCode: '300203', voucherNo: 'CLR/2607/0041', accountNo: 'CHQ-000534', accountName: 'XYZ Traders', particulars: 'Cheque Return - Insufficient Funds - XYZ Traders', debit: 33000, credit: 0 }, { glCode: '300203', voucherNo: 'CLR/2607/0042', accountNo: 'CHQ-000541', accountName: 'Om Textiles', particulars: 'Cheque Return - Insufficient Funds - Om Textiles', debit: 25000, credit: 0 }, // 300204 - CTS Clearing Difference Account (credit 12500 / debit 11000) { glCode: '300204', voucherNo: 'CLR/2607/0043', accountNo: 'CTS-GRID-01A', accountName: 'CTS Grid Rounding Adjustment - Batch 1 (Cr)', particulars: 'CTS Grid Rounding Adjustment - Batch 1', debit: 0, credit: 7500 }, { glCode: '300204', voucherNo: 'CLR/2607/0044', accountNo: 'CTS-GRID-01B', accountName: 'CTS Grid Rounding Adjustment - Batch 2 (Cr)', particulars: 'CTS Grid Rounding Adjustment - Batch 2', debit: 0, credit: 5000 }, { glCode: '300204', voucherNo: 'CLR/2607/0045', accountNo: 'CTS-GRID-02A', accountName: 'CTS Grid Rounding Adjustment - Batch 1 (Dr)', particulars: 'CTS Grid Rounding Adjustment - Batch 1', debit: 6500, credit: 0 }, { glCode: '300204', voucherNo: 'CLR/2607/0046', accountNo: 'CTS-GRID-02B', accountName: 'CTS Grid Rounding Adjustment - Batch 2 (Dr)', particulars: 'CTS Grid Rounding Adjustment - Batch 2', debit: 4500, credit: 0 }, // 300205 - Local Clearing House Account (credit 310000 / debit 292000) { glCode: '300205', voucherNo: 'CLR/2607/0047', accountNo: 'MUM-CH-S1', accountName: 'Mumbai Clearing House - Session I', particulars: 'CTS Grid Settlement - Session I (Cr)', debit: 0, credit: 180000 }, { glCode: '300205', voucherNo: 'CLR/2607/0048', accountNo: 'MUM-CH-S2', accountName: 'Mumbai Clearing House - Session II', particulars: 'CTS Grid Settlement - Session II (Cr)', debit: 0, credit: 130000 }, { glCode: '300205', voucherNo: 'CLR/2607/0049', accountNo: 'MUM-CH-S1D', accountName: 'Mumbai Clearing House - Session I', particulars: 'CTS Grid Settlement - Session I (Dr)', debit: 165000, credit: 0 }, { glCode: '300205', voucherNo: 'CLR/2607/0050', accountNo: 'MUM-CH-S2D', accountName: 'Mumbai Clearing House - Session II', particulars: 'CTS Grid Settlement - Session II (Dr)', debit: 127000, credit: 0 } ]; digitalTxns: TxnRow[] = [ // RTGS - Overall (credit 4850000 / debit 4620000) { glCode: 'RTGS', voucherNo: 'RTGS/2607/8891', accountNo: 'UTR-RTGS26073100234', accountName: 'Deepak Enterprises', particulars: 'RTGS Inward - Remitting Bank HDFC', debit: 0, credit: 2200000 }, { glCode: 'RTGS', voucherNo: 'RTGS/2607/8892', accountNo: 'UTR-RTGS26073100256', accountName: 'Reliance Distributors Pvt Ltd', particulars: 'RTGS Inward - Remitting Bank ICICI', debit: 0, credit: 1650000 }, { glCode: 'RTGS', voucherNo: 'RTGS/2607/8893', accountNo: 'UTR-RTGS26073100278', accountName: 'Wadia Constructions', particulars: 'RTGS Inward - Remitting Bank Axis', debit: 0, credit: 1000000 }, { glCode: 'RTGS', voucherNo: 'RTGS/2607/8894', accountNo: 'UTR-RTGS26073100891', accountName: 'Kunal Manufacturing Co.', particulars: 'RTGS Outward - Beneficiary Bank HDFC', debit: 2000000, credit: 0 }, { glCode: 'RTGS', voucherNo: 'RTGS/2607/8895', accountNo: 'UTR-RTGS26073100904', accountName: 'Bansal Steel Traders', particulars: 'RTGS Outward - Beneficiary Bank SBI', debit: 1600000, credit: 0 }, { glCode: 'RTGS', voucherNo: 'RTGS/2607/8896', accountNo: 'UTR-RTGS26073100918', accountName: 'Mehta Exports', particulars: 'RTGS Outward - Beneficiary Bank ICICI', debit: 1020000, credit: 0 }, // NEFT - Overall (credit 3260000 / debit 3105000) { glCode: 'NEFT', voucherNo: 'NEFT/2607/6712', accountNo: 'UTR-NEFT26073100589', accountName: 'Priya Sharma', particulars: 'NEFT Inward - Remitting Bank SBI', debit: 0, credit: 1500000 }, { glCode: 'NEFT', voucherNo: 'NEFT/2607/6713', accountNo: 'UTR-NEFT26073100601', accountName: 'Kunal Oberoi', particulars: 'NEFT Inward - Remitting Bank HDFC', debit: 0, credit: 1100000 }, { glCode: 'NEFT', voucherNo: 'NEFT/2607/6714', accountNo: 'UTR-NEFT26073100617', accountName: 'Sanya Kapoor', particulars: 'NEFT Inward - Remitting Bank ICICI', debit: 0, credit: 660000 }, { glCode: 'NEFT', voucherNo: 'NEFT/2607/6715', accountNo: 'UTR-NEFT26073100742', accountName: 'Sanjay Wholesale Traders', particulars: 'NEFT Outward - Beneficiary Bank SBI', debit: 1400000, credit: 0 }, { glCode: 'NEFT', voucherNo: 'NEFT/2607/6716', accountNo: 'UTR-NEFT26073100758', accountName: 'Rakesh Chandok', particulars: 'NEFT Outward - Beneficiary Bank Axis', debit: 1000000, credit: 0 }, { glCode: 'NEFT', voucherNo: 'NEFT/2607/6717', accountNo: 'UTR-NEFT26073100763', accountName: 'Meera Iyer', particulars: 'NEFT Outward - Beneficiary Bank HDFC', debit: 705000, credit: 0 }, // UPI - Overall (credit 5480000 / debit 5390000) - NPCI settlement batched by time slot { glCode: 'UPI', voucherNo: 'UPI/2607/44521', accountNo: 'RRN-UPI26073100145', accountName: 'UPI Inward Settlement - Morning Batch (00:00-12:00)', particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)', debit: 0, credit: 1980000 }, { glCode: 'UPI', voucherNo: 'UPI/2607/44522', accountNo: 'RRN-UPI26073100289', accountName: 'UPI Inward Settlement - Afternoon Batch (12:00-18:00)', particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)', debit: 0, credit: 2100000 }, { glCode: 'UPI', voucherNo: 'UPI/2607/44523', accountNo: 'RRN-UPI26073100356', accountName: 'UPI Inward Settlement - Evening Batch (18:00-24:00)', particulars: 'UPI Collect - Merchant/P2P Inward (Aggregated)', debit: 0, credit: 1400000 }, { glCode: 'UPI', voucherNo: 'UPI/2607/44524', accountNo: 'RRN-UPI26073100478', accountName: 'UPI Outward Settlement - Morning Batch (00:00-12:00)', particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)', debit: 1850000, credit: 0 }, { glCode: 'UPI', voucherNo: 'UPI/2607/44525', accountNo: 'RRN-UPI26073100512', accountName: 'UPI Outward Settlement - Afternoon Batch (12:00-18:00)', particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)', debit: 2050000, credit: 0 }, { glCode: 'UPI', voucherNo: 'UPI/2607/44526', accountNo: 'RRN-UPI26073100634', accountName: 'UPI Outward Settlement - Evening Batch (18:00-24:00)', particulars: 'UPI Pay - Merchant/P2P Outward (Aggregated)', debit: 1490000, credit: 0 }, // ATM - Overall (credit 210000 / debit 685000) { glCode: 'ATM', voucherNo: 'ATM/2607/9081', accountNo: 'RRN-ATM26073100118', accountName: 'ATM Cash Deposits - Own Branch ATM (Aggregated)', particulars: 'ATM Cash Deposit - Own Branch ATM', debit: 0, credit: 150000 }, { glCode: 'ATM', voucherNo: 'ATM/2607/9082', accountNo: 'RRN-ATM26073100224', accountName: 'ATM Cash Deposits - Extension Counter ATM (Aggregated)', particulars: 'ATM Cash Deposit - Extension Counter ATM', debit: 0, credit: 60000 }, { glCode: 'ATM', voucherNo: 'ATM/2607/9083', accountNo: 'RRN-ATM26073100337', accountName: 'ATM Cash Withdrawals - Own Branch ATM (Aggregated)', particulars: 'ATM Cash Withdrawal - Own Branch ATM', debit: 420000, credit: 0 }, { glCode: 'ATM', voucherNo: 'ATM/2607/9084', accountNo: 'RRN-ATM26073100449', accountName: 'ATM Cash Withdrawals - Other Bank ATM, NFS Switch (Aggregated)', particulars: 'ATM Cash Withdrawal - Other Bank ATM (NFS)', debit: 265000, credit: 0 }, // NACH - Overall (credit 940000 / debit 865000) { glCode: 'NACH', voucherNo: 'NACH/2607/3304', accountNo: 'UMRN-NACH26073100112', accountName: 'NACH Credits - Corporate Payroll Disbursement (Aggregated)', particulars: 'NACH Credit - Salary Disbursement Batch', debit: 0, credit: 650000 }, { glCode: 'NACH', voucherNo: 'NACH/2607/3305', accountNo: 'UMRN-NACH26073100156', accountName: 'NACH Credits - Government Subsidy (DBT) Disbursement (Aggregated)', particulars: 'NACH Credit - Subsidy Disbursement Batch', debit: 0, credit: 290000 }, { glCode: 'NACH', voucherNo: 'NACH/2607/3306', accountNo: 'UMRN-NACH26073100198', accountName: 'NACH Debits - Retail Loan EMI Collection (Aggregated)', particulars: 'NACH Debit - Loan EMI Collection Batch', debit: 560000, credit: 0 }, { glCode: 'NACH', voucherNo: 'NACH/2607/3307', accountNo: 'UMRN-NACH26073100233', accountName: 'NACH Debits - Gold Loan EMI Collection (Aggregated)', particulars: 'NACH Debit - Gold Loan EMI Collection Batch', debit: 305000, credit: 0 } ]; /** 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() { const d = new Date(); 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(); this.isHeadOffice = this.auth.isHeadOfficeUser(); this.currentOfficeName = creds?.officeName || 'Branch Office'; if (this.isHeadOffice) { // Head Office starts on the consolidated view and can drill into either branch. this.selectedBranchCode = 'ALL'; } else { // Match the logged-in office's real name to one of the two dummy branches, so each // branch's login shows its own figures. Falls back to the unscaled base dataset // (still labelled with the user's real office name) if no branch name matches. this.ownBranch = this.branches.find((b) => this.currentOfficeName.toLowerCase().includes(b.name.toLowerCase())) || null; this.selectedBranchCode = this.ownBranch?.code || 'OWN'; } } /** 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[] { switch (tab) { case 'cash': return this.cashRows; case 'transfer': return this.transferRows; case 'clearing': return this.clearingRows; case 'digital': return this.digitalRows; } } private baseTxnsFor(tab: TabKey): TxnRow[] { switch (tab) { case 'cash': return this.cashTxns; case 'transfer': return this.transferTxns; case 'clearing': return this.clearingTxns; case 'digital': return this.digitalTxns; } } private roundAmt(v: number): number { return Math.round(v / 100) * 100; } private scaleRows(rows: SummaryRow[], factor: number): SummaryRow[] { if (factor === 1) { return rows; } return rows.map((r) => ({ ...r, opening: this.roundAmt(r.opening * factor) })); } /** * 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.map((t) => ({ ...t, voucherNo: `${branch.code}-${t.voucherNo}`, accountNo: this.scaleAccountNo(t.accountNo, branch), debit: this.roundAmt(t.debit * branch.scale), credit: this.roundAmt(t.credit * branch.scale) })); } /** Rows for a given tab, scoped to the currently selected branch (or consolidated across both, for Head Office). */ private effectiveRows(tab: TabKey): SummaryRow[] { const base = this.baseRowsFor(tab); if (!this.isHeadOffice) { return this.ownBranch ? this.scaleRows(base, this.ownBranch.scale) : base; } if (this.selectedBranchCode === 'ALL') { return base.map((r) => ({ ...r, opening: this.branches.reduce((sum, b) => sum + this.roundAmt(r.opening * b.scale), 0) })); } const branch = this.branches.find((b) => b.code === this.selectedBranchCode); return this.scaleRows(base, branch ? branch.scale : 1); } /** Transactions for a given tab, scoped to the currently selected branch (or merged across both, for Head Office). */ private effectiveTxns(tab: TabKey): TxnRow[] { const base = this.baseTxnsFor(tab); if (!this.isHeadOffice) { return this.scaleTxns(base, this.ownBranch); } if (this.selectedBranchCode === 'ALL') { return this.branches.flatMap((b) => this.scaleTxns(base, b)); } const branch = this.branches.find((b) => b.code === this.selectedBranchCode); return this.scaleTxns(base, branch ?? null); } get rowsForActiveTab(): SummaryRow[] { return this.effectiveRows(this.activeTab); } get txnsForActiveTab(): TxnRow[] { return this.effectiveTxns(this.activeTab); } /** Name of the branch/scope currently being viewed, for display in the header. */ get scopeName(): string { if (!this.isHeadOffice) { return this.currentOfficeName; } if (this.selectedBranchCode === 'ALL') { return 'All Branches (Consolidated)'; } return this.branches.find((b) => b.code === this.selectedBranchCode)?.name || ''; } setBranch(code: string): void { this.selectedBranchCode = code; this.glFilter = null; } setTab(tab: TabKey): void { this.activeTab = tab; this.glFilter = null; } toggleDetails(): void { this.showDetails = !this.showDetails; this.glFilter = null; } setGlFilter(code: string | null): void { this.glFilter = code; } /** Transactions for the Transaction Details view, narrowed to the selected GL/channel filter (or all, when null). */ get filteredTxns(): TxnRow[] { if (!this.glFilter) { return this.txnsForActiveTab; } return this.txnsForActiveTab.filter((t) => t.glCode === this.glFilter); } /** Short label for a GL filter chip — the channel code for Digital (RTGS/NEFT/...), the GL name otherwise. */ filterLabel(row: SummaryRow): string { return this.activeTab === 'digital' ? row.code : row.name; } /** GL name for the code tracked on this txn row, so the Transaction Details journal can show * "which GL" alongside the account, not just a bare code. */ glName(code: string): string { return this.rowsForActiveTab.find((r) => r.code === code)?.name || code; } /** * Every transaction here is only ever recorded as ONE leg (whichever GL this Cash/Clearing/ * Transfer/Digital screen tracks) — the offsetting leg (the customer's own account, a * settlement/clearing-house account, etc.) was never modelled as a separate GL row. Rather * than leaving that side blank, this derives a sensible label for it so the Transaction * Details view can show the FULL double entry (Dr leg + Cr leg, always equal amounts) — * exactly what a real CBS "Day Book"/Journal Register shows, and what makes it possible to * see at a glance that a transaction is complete and ready for reconciliation. * * For internal cash-movement postings (ATM cash-in-transit, currency chest, denomination * shortages, CTS grid rounding) the account name already describes the SAME leg rather than a * distinct counter-party, so those get a purpose-built contra label. Everything else already * has a descriptive counter-party name (customer, vendor, bank branch, government department) * that IS the natural contra account, so it's used as-is — WITHOUT repeating the account/ * reference number, since that number is already shown against the tracked GL leg on the * other line; showing it a second time here would make both lines look like the same account, * defeating the point of a "Balanced" two-sided entry. */ contraLabel(t: TxnRow): string { const p = t.particulars.toLowerCase(); if (p.includes('atm') && (p.includes('vault') || p.includes('loading') || p.includes('surrendered'))) { return 'ATM Cash-in-Transit Account'; } if (p.includes('currency chest')) { return 'Currency Chest Account (Sponsor Bank)'; } if (p.includes('denomination') || p.includes('shortage adjustment')) { return 'Cash Difference / Shortage Suspense Account'; } if (p.includes('cts grid rounding')) { return 'CTS Grid Rounding Suspense Account'; } return t.accountName; } /** The single non-zero amount on this leg — always what the derived contra leg mirrors. */ legAmount(t: TxnRow): number { return t.debit > 0 ? t.debit : t.credit; } /** Credit total for a GL row — always summed from its own txn lines, never a separate hand-entered number. */ rowCredit(row: SummaryRow, txns: TxnRow[]): number { return txns.filter((t) => t.glCode === row.code).reduce((sum, t) => sum + t.credit, 0); } /** Debit total for a GL row — always summed from its own txn lines, never a separate hand-entered number. */ rowDebit(row: SummaryRow, txns: TxnRow[]): number { return txns.filter((t) => t.glCode === row.code).reduce((sum, t) => sum + t.debit, 0); } closing(row: SummaryRow, txns: TxnRow[]): number { return row.opening + this.rowCredit(row, txns) - this.rowDebit(row, txns); } total(rows: SummaryRow[], txns: TxnRow[], key: 'opening' | 'credit' | 'debit'): number { if (key === 'opening') { return rows.reduce((sum, r) => sum + r.opening, 0); } if (key === 'credit') { return rows.reduce((sum, r) => sum + this.rowCredit(r, txns), 0); } return rows.reduce((sum, r) => sum + this.rowDebit(r, txns), 0); } totalClosing(rows: SummaryRow[], txns: TxnRow[]): number { return this.total(rows, txns, 'opening') + this.total(rows, txns, 'credit') - this.total(rows, txns, 'debit'); } txnTotal(rows: TxnRow[], key: 'debit' | 'credit'): number { return rows.reduce((sum, r) => sum + r[key], 0); } private readonly allTabs: TabKey[] = [ 'cash', 'transfer', 'clearing', 'digital' ]; /** Cash/Transfer/Clearing/Digital category pairs, scoped to the currently selected branch. */ private get categories(): Array<{ rows: SummaryRow[]; txns: TxnRow[] }> { return this.allTabs.map((tab) => ({ rows: this.effectiveRows(tab), txns: this.effectiveTxns(tab) })); } get grandOpening(): number { return this.categories.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'opening'), 0); } get grandCredit(): number { return this.categories.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'credit'), 0); } get grandDebit(): number { return this.categories.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'debit'), 0); } get grandClosing(): number { return this.grandOpening + this.grandCredit - this.grandDebit; } /** * Branch-wise contribution to the day's overall position — shown only to Head Office * users while viewing "All Branches". Each branch's figures are derived the same way * (opening scaled, credit/debit summed from that branch's own scaled txns), so this * table can never drift from what you'd see by drilling into that branch individually. */ get branchBreakup(): Array<{ code: string; name: string; opening: number; credit: number; debit: number; closing: number; }> { return this.branches.map((b) => { const pairs = this.allTabs.map((tab) => ({ rows: this.scaleRows(this.baseRowsFor(tab), b.scale), txns: this.scaleTxns(this.baseTxnsFor(tab), b) })); 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 debit = pairs.reduce((sum, c) => sum + this.total(c.rows, c.txns, 'debit'), 0); return { code: b.code, name: b.name, opening, credit, debit, closing: opening + credit - debit }; }); } /** * Exports the full report for the currently viewed scope (own branch, a drilled-into branch, * or "All Branches" consolidated) — every category (Cash/Transfer/Clearing/Digital), not just * the tab on screen, so the workbook is a complete record. "Summary" mirrors the Opening/ * Credit/Debit/Closing view; "Transaction Details" mirrors the full double-entry journal view * (same glName/contraLabel/legAmount derivations, so the export can never disagree with what's * on screen); "Branch Breakup" is added only when Head Office is viewing the consolidated view. */ async exportExcel(): Promise { this.generating = true; try { const summaryRows: (string | number | null)[][] = []; const journalRows: (string | number | null)[][] = []; for (const tab of this.allTabs) { const label = this.tabLabels[tab]; const rows = this.effectiveRows(tab); const txns = this.effectiveTxns(tab); rows.forEach((r) => { summaryRows.push([ label, r.code, r.name, r.opening, this.rowCredit(r, txns), this.rowDebit(r, txns), this.closing(r, txns) ]); }); summaryRows.push([ `${label} Total`, '', '', this.total(rows, txns, 'opening'), this.total(rows, txns, 'credit'), this.total(rows, txns, 'debit'), this.totalClosing(rows, txns) ]); txns.forEach((t) => { const glText = rows.find((r) => r.code === t.glCode)?.name || t.glCode; journalRows.push([ label, this.asOnDate, this.display(t.voucherNo), 'Dr', t.debit > 0 ? t.glCode : '', t.debit > 0 ? `${glText} — ${this.display(t.accountNo)} (${t.accountName})` : this.contraLabel(t), this.legAmount(t), null, 'Balanced' ]); journalRows.push([ label, this.asOnDate, this.display(t.voucherNo), 'Cr', t.credit > 0 ? t.glCode : '', t.credit > 0 ? `${glText} — ${this.display(t.accountNo)} (${t.accountName})` : this.contraLabel(t), null, this.legAmount(t), 'Balanced' ]); }); } summaryRows.push([ 'Grand Total', '', '', this.grandOpening, this.grandCredit, this.grandDebit, this.grandClosing ]); const sheets: ExportSheetSpec[] = [ { sheetName: 'Summary', title: 'Cash / Clearing / Transfer - Summary Report', subtitle: `Scope: ${this.scopeName} · As On: ${this.asOnDate}`, headers: [ 'Category', 'GL Code', 'Particulars', 'Opening', 'Credit', 'Debit', 'Closing' ], widths: [ 12, 12, 34, 16, 16, 16, 16 ], rows: summaryRows }, { sheetName: 'Transaction Details', title: 'Transaction Details — Full Double Entry', subtitle: `Scope: ${this.scopeName} · As On: ${this.asOnDate}`, headers: [ 'Category', 'Date', 'Voucher / Ref No', 'Dr / Cr', 'GL Code', 'GL / Account', 'Debit', 'Credit', 'Status' ], widths: [ 12, 12, 20, 8, 10, 46, 16, 16, 12 ], rows: journalRows } ]; if (this.isHeadOffice && this.selectedBranchCode === 'ALL') { sheets.push({ sheetName: 'Branch Breakup', title: 'Branch-wise Break-up', subtitle: `As On: ${this.asOnDate}`, headers: [ 'Branch', 'Opening', 'Credit', 'Debit', 'Closing' ], widths: [ 22, 16, 16, 16, 16 ], rows: [ ...this.branchBreakup.map((b) => [ b.name, b.opening, b.credit, b.debit, b.closing ]), [ 'All Branches', this.grandOpening, this.grandCredit, this.grandDebit, this.grandClosing ] ] }); } await exportWorkbook(sheets, `Cash-Clearing-Transfer-Summary-${this.scopeName}-${this.asOnDate}`); } catch (err) { console.error('Cash/Clearing/Transfer export failed', err); } finally { this.generating = false; } } }